Pergunta

Eu acho que deveria ser 01, mas alguém diz que é "indefinido", qualquer motivo para isso?

Foi útil?

Solução

c++ é um incremento e uma tarefa. Quando a atribuição ocorre (antes ou depois de outro código nessa linha) é deixada a critério do compilador. Pode ocorrer após o cout << ou antes.

Isso pode ser encontrado no padrão C99 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

Você pode encontrá -lo na página 28 no PDF ou na Seção 5.1.2.3

O incremento real de p pode ocorrer a qualquer momento entre o ponto de sequência anterior e o próximo ponto de sequência

Como alguém pediu o padrão C ++ (como essa é uma pergunta C ++), ele pode ser encontrado na Seção 1.9.15 Página 10 (ou 24 no formato PDF)

Avaliações de operandos de operadores individuais e de subexpressões de expressões individuais não são sequenciados

Ele também inclui o seguinte bloco de código:

i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined

Sinto que a explicação do padrão C99 é mais clara, mas é verdade nos dois idiomas.

Outras dicas

É um comportamento indefinido se você modificar um valor e, em seguida, leia -o (ou tente modificá -lo novamente) sem um ponto de sequência interveniente. O conceito de um ponto de sequência em C ++ é um pouco técnico (você pode ler um pouco sobre isso aqui), mas a linha inferior é que a inserção do fluxo (<<) é não um ponto de sequência.

A razão pela qual esse é um comportamento indefinido é porque, na ausência de um ponto de sequência, o compilador pode reordenar as operações de qualquer maneira que considere adequado. Isto é, é permitido recuperar o valor de c (e segure -o para a segunda inserção) e depois execute as palavras c++ Para obter o valor para a primeira inserção. Portanto, você não pode ter certeza se o incremento ocorrerá antes ou depois do valor de c Para a segunda inserção, é determinado.

A razão pela qual está indefinida é que o compilador está livre para calcular parâmetros de função em qualquer ordem. Considere se você está chamando uma função (porque você é, mas é mais fácil de imaginar quando está na sintaxe da função):


  cout.output(c++).output(c);

O compilador pode atingir os parâmetros em ordem inversa, ordem direta ou qualquer outra coisa. Ele pode chamar a primeira saída antes de calcular o parâmetro para a segunda saída ou pode fazer as duas e depois ligar.

O comportamento é definido, mas não especificado. A ordem relativa de avaliar os dois usos de 'C' na expressão não é especificada. No entanto, se você o converter em notação funcional, parece esta:

cout.operator<<(c++).operator<<(c);

Há um ponto de sequência entre avaliar os argumentos para uma função e executar o corpo da função, e os corpos da função não são intercalados; portanto, o resultado é apenas não especificado, não um comportamento indefinido.

Se você não tinha um operador sobrecarregado:

int c=0;
int a = c++ << c;

Então o comportamento seria indefinido, porque modificando e usando o valor de c sem um ponto de sequência interveniente.

Editar: a sequência litb traz à tona está simplesmente errado. O padrão especifica (§1.9/17): "Ao chamar uma função (se a função está ou não embutida), há um ponto de sequência após a avaliação de todos os argumentos da função (se houver) que ocorram antes da execução de quaisquer expressões ou declarações no corpo da função. "

Isso claramente escrito com a idéia de que os argumentos são avaliados e, em seguida, (imediatamente depois) o corpo da função é executado. A sequência que ele sugere, em que os argumentos para uma função são avaliados, depois os argumentos para outro, depois a execução de ambos os órgãos de função não parece ter sido planejada, mas também não é proibido. Isso, no entanto, não muda nada - o requisito ainda é que: "... existe um ponto de sequência após a avaliação de todos os argumentos da função (se houver) ..."

A linguagem subsequente sobre a execução do corpo não remove o requisito para um ponto de sequência após avaliar todos os argumentos da função. Tudo Outra avaliação, se do corpo da função ou outros argumentos da função segue esse ponto de sequência. Eu posso ser tão pedante e perverso quanto qualquer um sobre ler mal o que é claramente pretendido (mas não bastante declarado) - mas não consigo imaginar como "existe um ponto de sequência após a avaliação de todos os argumentos da função" pode ser lida como significado "não há um ponto de sequência após a avaliação de todos os argumentos da função".

O ponto de Neil é, é claro, correto: a sintaxe que usei acima é para funções de membro. Para uma sobrecarga não-membro, a sintaxe seria mais como:

operator<<(operator<<(cout,c++), c);

Isso também não remove o requisito para pontos de sequência.

Tanto quanto não é especificado: é realmente simples: há um ponto de sequência depois de avaliar todos os argumentos da função; portanto, todos os argumentos para uma chamada de função devem ser totalmente avaliados (incluindo todos os efeitos colaterais), então os argumentos para a outra chamada de função podem ser avaliado (levando em consideração quaisquer efeitos colaterais do outro) - mas não há requisito sobre quais argumentos de chamadas de função devem ser avaliados primeiro ou segundo c, então c++, ou pode ser c++, então c - mas tem que ser um ou outro, não uma intercalação.

A meu ver, f (c ++); é equivalente a: f (c); c += 1;

E f (c ++, c ++); é equivalente a: f (c, c); c += 1; c += 1;

Mas pode ser o caso de F (C ++, C ++); torna -se f (c, c+1); c+= 2;

Um experimento com GCC e CLANG, primeiro em C

#include <stdio.h>

void f(int a, int b) {
    printf("%d %d\n",a,b);
}

int main(int argc, char **argv) {
    int c = 0;
    f(c++,c++);

    return 0;
}

e em C ++

#include <iostream>

int main(int argc, char **argv) {
    int c = 0;
    std::cout << c++ << " " << c++ << std::endl;
    return 0;
}

É interessante, pois o GCC e o G ++ compilam em 1 0, enquanto Clang compilou em 0 1

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top