Para i = 0, por que (i + = i ++) é igual a 0?


253

Pegue o seguinte código (utilizável como um aplicativo de console):

static void Main(string[] args)
{
    int i = 0;
    i += i++;
    Console.WriteLine(i);
    Console.ReadLine();
}

O resultado ié 0. Eu esperava 2 (como alguns de meus colegas fizeram). Provavelmente, o compilador cria algum tipo de estrutura que resulta em izero.

A razão pela qual eu esperava 2 é que, na minha linha de pensamento, a instrução da direita seria avaliada primeiro, incrementando i com 1. A seguir, ela é adicionada a i. Como eu já sou 1, ele adiciona 1 a 1. Então 1 + 1 = 2. Obviamente, não é isso que está acontecendo.

Você pode explicar o que o compilador faz ou o que acontece no tempo de execução? Por que o resultado é zero?

Algum tipo de aviso: estou absolutamente ciente de que você não (e provavelmente não deveria) usar esse código. Eu sei que nunca vou. No entanto, acho interessante saber por que ele age dessa maneira e o que está acontecendo exatamente.


57
o resultado esperado não deve ser 1? i (0) + = i ++ (1) portanto 0 + = 1 = 1
aleation

11
Funciona como esperado
Steve é ​​D D

177
Quantas variações dessa pergunta serão feitas?
mowwwalker

20
Preincrementation irá incrementar valor antes de fazer o Acction i + = ++ i lhe dará 1
Pierluc SS

21
Por que todo mundo está focado no pré-pós-incremento? A coisa "estranha" é que o valor do ilado esquerdo de +=é "armazenado em cache" antes da avaliação do lado direito. Isso é contra-intuitivo, pois exigiria, por exemplo, uma operação de cópia se ifosse um objeto. (Por favor, não me mis-compreender: Eu concordo absolutamente a afirmar que 0é a resposta correta e padrão-conformidade.)
JohnB

Respostas:


425

Este:

int i = 0;
i += i++

Pode ser visto como você está fazendo (a seguir é uma simplificação grosseira):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

O que realmente acontece está mais envolvido do que isso - dê uma olhada no MSDN, 7.5.9 Operadores de incremento e decremento do Postfix :

O processamento em tempo de execução de uma operação de incremento ou decremento do postfix no formato x ++ ou x-- consiste nas seguintes etapas:

  • Se x é classificado como uma variável:

    • x é avaliado para produzir a variável.
    • O valor de x é salvo.
    • O operador selecionado é chamado com o valor salvo de x como argumento.
    • O valor retornado pelo operador é armazenado no local indicado pela avaliação de x.
    • O valor salvo de x se torna o resultado da operação.

Observe que, devido à ordem de precedência , o postfix ++ocorre antes += , mas o resultado acaba não sendo utilizado (como o valor anterior de ié usado).


Uma decomposição mais completa das i += i++partes de que é feita exige que se saiba que ambas são +=e ++não são atômicas (ou seja, nenhuma é uma operação única), mesmo que pareçam ser. A maneira como elas são implementadas envolve variáveis ​​temporárias, cópias de iantes das operações - uma para cada operação. (Usarei os nomes iAdde iAssignas variáveis ​​temporárias usadas para ++e +=respectivamente).

Portanto, uma aproximação mais próxima do que está acontecendo seria:

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;

3
@Oded A ++operação é realizada antes da conclusão da avaliação da declaração. Então, +=substitui o valor. Foi isso que aconteceu?
Anirudh Ramanathan

6
@Oded realmente seu: int i = 0; i = i + 1; (postfix) i = 0; (assignment). Se você usou i em outro lugar nessa declaração, ele avaliaria como 1 por vez.
drch

@Cthulhu - Essencialmente. A resposta por dtb entra nos detalhes.
Oded

6
Eu não compro este. A resposta de @yoriy é muito mais precisa. Por um lado, em sua resposta, você diz que a última linha seria o i+1que deveria ser i=i+1. Não é isso o que i++é?
recluze

3
A primeira parte da resposta é redundante. Seu último exemplo de código poderia ter feito isso IMHO. +1 embora.
Corazza 27/11/12

194

Desmontagem do código em execução:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

Código equivalente

Compila para o mesmo código que o seguinte código:

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

Desmontagem do segundo código (apenas para provar que são os mesmos)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

Abrir janela de desmontagem

A maioria das pessoas não sabe, ou nem se lembra, que pode ver o código final da montagem na memória, usando a janela Desmontagem do Visual Studio . Mostra o código da máquina que está sendo executado, não é CIL.

Use isso durante a depuração:

Debug (menu) -> Windows (submenu) -> Disassembly

Então, o que está acontecendo com o postfix ++?

O postfix ++ diz que gostaríamos de aumentar o valor do operando após a avaliação ... que todo mundo sabe ... o que confunde um pouco é o significado de "após a avaliação" .

Então, o que significa "após a avaliação" significa:

  • outros usos do operando, na mesma linha de código devem ser afetados:
    • a = i++ + i o segundo i é afetado pelo incremento
    • Func(i++, i) o segundo i é afetado
  • outros usos na mesma linha respeitam o operador de curto-circuito como ||e &&:
    • (false && i++ != i) || i == 0 o terceiro i não é afetado pelo i ++ porque não é avaliado

Então, qual é o significado de i += i++;:?

É o mesmo que i = i + i++;

A ordem da avaliação é:

  1. Armazenar i + i (ou seja, 0 + 0)
  2. Incremento i (i se torna 1)
  3. Atribua o valor da etapa 1 a i (i se torna 0)

Não que o incremento esteja sendo descartado.

Qual é o significado de i = i++ + i;:?

Isso não é o mesmo que no exemplo anterior. O terceiro ié afetado pelo incremento.

A ordem da avaliação é:

  1. Armazenar i (que é 0)
  2. Incremento i (i se torna 1)
  3. Armazene o valor da etapa 1 + i (que é 0 + 1)
  4. Atribua o valor da etapa 3 a i (i se torna 1)

22
+ 1 ++ - para pura dissecação grave. Chuck Norris seria orgulhoso :) Eu acho que você fizer a suposição de que o OP é em Intel, não uma porta Mono embora ...
StuartLC

19
O C # tem uma ordem de avaliação bem definida para a expressão e o código do objeto apenas implementa essa ordem. A saída do código da máquina não é o motivo ou a explicação para a ordem de avaliação.
Kaz

8
O código da máquina facilita a compreensão de como a ordem de avaliação é implementada na IMO.
23712 Kevin

5
@StuartLC Eu vejo o que você fez lá. Vergonha sobre isso descartado upvote embora.
precisa

2
a++ + anão é o mesmo a + a++porque isso não é mais pura matemática. A lei da comutatividade na álgebra não leva em consideração a possibilidade de as variáveis ​​mudarem de valor no meio de uma expressão. A matemática apenas mapeia perfeitamente a programação quando a programação é uma programação funcional. E nem mesmo por causa de limitações representacionais. Por exemplo, números de ponto flutuante às vezes se comportam como reais e às vezes não. Mesmo sem efeitos colaterais, as leis de comutatividade e associatividade que se aplicam a números reais na matemática quebram sobre números de ponto flutuante.
Kaz

61
int i = 0;
i += i++;

é avaliado da seguinte maneira:

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

ie ié alterado duas vezes: uma vez pela i++expressão e uma vez pela +=declaração.

Mas os operandos da +=declaração são

  • o valor iantes da avaliação de i++(lado esquerdo de +=) e
  • o valor iantes da avaliação de i++(lado direito de +=).

Ah, essa é uma explicação fantástica. Lembra-me de quando trabalhei em uma calculadora baseada em pilha usando a notação de polimento reverso.
Nathan

36

Primeiro, i++retorna 0. Em seguida, ié incrementado por 1. Por último, ié definido o valor inicial ique é 0 mais o valor i++retornado, que também é zero. 0 + 0 = 0.


2
Mas não é i += i++;, i = i++;portanto o valor de i++(0) é adicionado ie não " ié definido como o valor i++retornado". Agora, a pergunta é: ao adicionar o valor i++retornado i, será io valor incrementado ou o valor não incrementado? A resposta, meu amigo, está escrita nas especificações.
Daniel Fischer

É verdade, eu vou consertar. Mas de qualquer maneira, desde i = 0inicialmente, i += somethingé equivalente a i = 0 + somethingqual é i = something.
Jong

32

Isso é simplesmente a avaliação ascendente da esquerda para a direita da árvore de sintaxe abstrata. Conceitualmente, a árvore da expressão é percorrida de cima para baixo, mas a avaliação se desdobra à medida que a recursão retorna a árvore de baixo para cima.

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

A avaliação começa considerando o nó raiz +=. Esse é o principal constituinte da expressão. O operando esquerdo de +=deve ser avaliado para determinar o local onde armazenamos a variável e para obter o valor anterior que é zero. Em seguida, o lado direito deve ser avaliado.

O lado direito é um ++operador pós-incremento . Ele possui um operando, ique é avaliado como fonte de um valor e como um local onde um valor deve ser armazenado. O operador avalia i, localiza 0e consequentemente armazena um 1nesse local. Retorna o valor anterior 0, de acordo com sua semântica de retornar o valor anterior.

Agora o controle está de volta ao +=operador. Agora ele tem todas as informações para concluir sua operação. Ele conhece o local onde armazenar o resultado (o local de armazenamento i), bem como o valor anterior, e possui o valor a ser adicionado ao valor anterior, a saber 0. Então, iacaba com zero.

Como o Java, o C # limpou um aspecto muito asinino da linguagem C, fixando a ordem da avaliação. Da esquerda para a direita, de baixo para cima: a ordem mais óbvia que provavelmente é esperada pelos codificadores.


+1: eu concordo com você, exceto que todo codificador espera que ... eu esperava que fosse o mesmo que algo assim: SetSum(ref i, Inc(ref i))com int SetSum(ref int a, int b) { return a += b; }e int Inc(ref int a) { return a++; }... é claro que não espero mais isso.
Miguel Angelo

Além disso, o que eu esperava é inconsistente! Não seria igual a Set(ref i, Sum(i, Inc(ref i)))com int Set(ref int a, int b) { return a = b; }e int Sum(int a, int b) { return a + b; }.
Miguel Angelo

Obrigado; você sugere uma falha / incompletude na minha resposta que eu tenho que corrigir.
Kaz

O problema SetSumé que ele não avalia o operando esquerdo i, mas apenas leva seu endereço, portanto, não é equivalente a uma avaliação completa do operando da esquerda para a direita. Você precisa de algo parecido SetSum(ref i, i, PostInc(ref i)). O segundo argumento de SetSumé o valor a ser adicionado, onde usamos apenas ipara especificar o valor anterior de i. SetSumé justo int SetSum(ref int dest, int a, int b) { return dest = a + b; }.
Kaz

A confusão acontece (pelo menos para mim) com o operador + =, porque o operador de atribuição tem avaliação da direita para a esquerda (por exemplo, a = b = c = d) ... para que se possa imaginar que + = segue a mesma regra, como uma operação atômica (como fiz com meu método SetSum) ... mas o que acontece de fato é que C # se traduz a += bem a = a + b... mostrando que o operador + = não é atômico ... é apenas açúcar sintático.
Miguel Angelo

30

Porque i++primeiro retorna o valor e depois o incrementa. Mas depois que i é definido como 1, você o define novamente como 0.


17

O método pós-incremento se parece com isso

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

Então, basicamente, quando você chama i++, ié incrementado, mas o valor original é retornado no seu caso, sendo 0 retornado.


12

Resposta simples

int i = 0;
i += i++;
// Translates to:
i = i + 0; // because post increment returns the current value 0 of i
// Before the above operation is set, i will be incremented to 1
// Now i gets set after the increment,
// so the original returned value of i will be taken.
i = 0;

12

i ++ significa: retornar o valor de i THEN incrementá-lo.

i + = i ++ significa: Pegue o valor atual de i. Adicione o resultado do i ++.

Agora, vamos adicionar i = 0 como condição inicial. i + = i ++ agora é avaliado assim:

  1. Qual é o valor atual de i? É 0. Armazene para que possamos adicionar o resultado do i ++.
  2. Avaliar i ++ (avalia como 0 porque esse é o valor atual de i)
  3. Carregue o valor armazenado e adicione o resultado da etapa 2 a ele. (adicione 0 a 0)

Nota: No final da etapa 2, o valor de i é realmente 1. No entanto, na etapa 3, você a descarta carregando o valor de i antes de ser incrementado.

Ao contrário de i ++, ++ i retorna o valor incrementado.

Portanto, i + = ++ eu daria a você 1.


É ajuda Full
sonsha 28/09/16

11

O operador de incremento pós-correção ++, fornece à variável um valor na expressão e, em seguida, efetua o incremento ao qual você atribuiu o valor zero (0) retornado inovamente que substitui o valor incrementado (1) , para que você esteja obtendo zero. Você pode ler mais sobre o operador de incremento no Operador ++ (MSDN).


8

i += i++; será igual a zero, porque faz o ++ depois.

i += ++i; vai fazer isso antes


4
Se isso acontecer ++depois, eu esperaria que o resultado fosse 1.
Comecme 22/11/2012

8

O postfix ++ é avaliado iantes de incrementá-lo e +=é avaliado apenas iuma vez.

Portanto, 0 + 0 = 0, como ié avaliado e usado antes de ser incrementado, conforme o formato do postfix de ++é usado. Para ser iincrementado primeiro, use o prefixo form ( ++i).

(Além disso, apenas uma observação: você deve obter apenas 1, pois 0 + (0 + 1) = 1)

Referências: http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+ =)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)


8

O que o C # está fazendo e o "porquê" da confusão

Eu também esperava que o valor fosse 1 ... mas alguma exploração sobre esse assunto esclareceu alguns pontos.

Considere os seguintes métodos:

    static int SetSum(ref int a, int b) { return a += b; }

    static int Inc(ref int a) { return a++; }

Eu esperava que i += i++fosse o mesmo que SetSum(ref i, Inc(ref i)). O valor de i após esta declaração é 1 :

int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1

Mas então cheguei a outra conclusão ... i += i++é realmente o mesmo que i = i + i++... então criei outro exemplo semelhante, usando estas funções:

    static int Sum(int a, int b) { return a + b; }

    static int Set(ref int a, int b) { return a = b; }

Depois de chamar isso, Set(ref i, Sum(i, Inc(ref i)))o valor de i é 0 :

int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0

Isso não apenas explica o que o C # está fazendo ... mas também porque muitas pessoas ficaram confusas com ele ... inclusive eu.


2
Adicione isso à sua resposta original, pois não traz nenhum benefício em tê-la como resposta separada.
casperOne

2
Fiz isso para não poluir a outra resposta, já que é sobre o código descompilado ... enquanto nesta, tentei uma abordagem diferente para explicar as coisas. O que você acha? Devo editar a outra resposta e acrescentar esta? Talvez, acrescente este ... não sei! Obrigado por sugestões!
Miguel Angelo

7

Um bom mnemônico que sempre me lembro disso é o seguinte:

Se ++estiver após a expressão, ele retornará o valor que era antes . Então, o código a seguir

int a = 1;
int b = a++;

é 1, porque aera 1 antes que aumentasse a ++posição depois a . As pessoas chamam essa postagem de notação de correção. Há também uma notação pré- fixada, na qual as coisas são exatamente o oposto: se ++estiver antes , a expressão retornará o valor que é após a operação:

int a = 1;
int b = ++a;

b tem dois aqui.

Então, para o seu código, isso significa

int i = 0;
i += (i++);

i++retorna 0 (como descrito acima), então 0 + 0 = 0.

i += (++i); // Here 'i' would become two

Scott Meyers descreve a diferença entre essas duas notações na "Programação C ++ eficaz". Internamente, i++(postfix) lembra que o valor iera e chama a notação de prefixo ( ++i) e retorna o valor antigo i,. É por isso que você deve allways usar ++iem forloops (embora eu acho que todos os compiladores modernos estão traduzindo i++para ++inos forlaços).


1
Eu testei int i = 0; i += (++i)e estou idefinido como um em vez de dois. Faz sentido para mim também, uma vez usando o prefixo em vez do postfix não muda o fato de que, se você escrever i += (++i)para i = i + (++i), a ié avaliada antes ++i, resultando em i = 0 + (++i)e, em última instância i = 0 + 1.
Wutz 29/08/13

6

A única resposta correta à sua pergunta é: Porque ela é indefinida.

Ok, antes que vocês todos me queimem ..

Todos vocês responderam por que i+=i++está correto e lógico resultar i=0.

Fiquei tentado a votar em cada uma das suas respostas, mas a reputação que calculei seria muito alta.

Por que estou tão bravo com vocês? não por causa do que suas respostas explicam.
Quero dizer, todas as respostas que li fizeram um esforço notável para explicar o impossível, aplaudo!

Mas qual é o resultado? é resultado intuitivo - é resultado aceitável?

Cada um de vocês viu o "rei nu" e de alguma forma o aceitou como um rei racional.

Vocês estão todos ERRADOS!

i+=i++;O resultado 0é indefinido.

um bug no mecanismo de avaliação de idiomas, se você quiser .. ou ainda pior! um bug no design.

quer uma prova? claro que você quer!

int t=0; int i=0; t+=i++; //t=0; i=1

Agora isso ... é resultado intuitivo! porque primeiro avaliamos a tatribuição com um valor e somente após a avaliação e a atribuição da operação pós-racional - não é racional?

é racional isso: i=i++e i=iproduzir o mesmo resultado para i?

enquanto t=i++e t=iter resultados diferentes parai .

A pós-operação é algo que deve ocorrer após a avaliação da instrução.
Portanto:

int i=0;
i+=i++;

Deve ser o mesmo se escrevemos:

int i=0;
i = i + i ++;

e, portanto, o mesmo que:

int i=0;
i= i + i;
i ++;

e, portanto, o mesmo que:

int i=0;
i = i + i;
i = i + 1;

Qualquer resultado que não seja 1 indique um erro no complier ou um erro no design da linguagem se formos com o pensamento racional - no entanto, o MSDN e muitas outras fontes nos dizem "ei - isso é indefinido!"

Agora, antes de continuar, mesmo este conjunto de exemplos que dei não é apoiado ou reconhecido por ninguém. No entanto, é isso que, de maneira intuitiva e racional, deveria ter sido o resultado.

O codificador não deve ter conhecimento de como o assembly está sendo escrito ou traduzido!

Se for escrito de uma maneira que não respeite as definições de linguagem - é um bug!

E para finalizar, copiei isso da Wikipedia : Operadores de incremento e decremento :
Como o operador de incremento / decremento modifica seu operando, o uso desse operando mais de uma vez na mesma expressão pode produzir resultados indefinidos . Por exemplo, em expressões como x - ++ x, não está claro em qual sequência os operadores de subtração e incremento devem ser executados. Situações como essa ficam ainda piores quando as otimizações são aplicadas pelo compilador, o que pode resultar na ordem de execução das operações diferente da pretendida pelo programador.

E portanto.

A resposta correta é que isso NÃO DEVE SER USADO! (como é indefinido!)

Sim .. - Tem resultados imprevisíveis, mesmo que o complemento de C # esteja tentando normalizá-lo de alguma forma.

Não encontrei nenhuma documentação do C # descrevendo o comportamento que todos vocês documentaram como um comportamento normal ou bem definido do idioma. O que eu encontrei é exatamente o oposto!

[ copiado da documentação do MSDN para operadores de incremento e decremento do Postfix: ++ e - ]

Quando um operador postfix é aplicado a um argumento de função, não é garantido que o valor do argumento seja incrementado ou decrementado antes de ser passado para a função. Consulte a seção 1.9.17 no padrão C ++ para obter mais informações.

Observe as palavras não garantidas ...

Perdoe-me se essa resposta parecer arrogante - eu não sou uma pessoa arrogante. Eu apenas considero que milhares de pessoas vêm aqui para aprender e as respostas que eu li as enganarão e prejudicarão sua lógica e compreensão do assunto.


Não sei se estou seguindo 100%, mas você faz referência à documentação do C ++, mas minha pergunta era sobre c #. A documentação sobre isso está aqui .
Peter Peter

Eu estava me referindo ao c # na minha resposta. No link que você forneceu: O resultado de x ++ ou x-- é o valor de x antes da operação, enquanto o resultado de ++ x ou --x é o valor de x após a operação. Nos dois casos, x em si tem o mesmo valor após a operação. mostra claramente que esse não é o caso ao testar .. porque i=++ifornecerá resultados diferentes i=i++. Portanto, minha resposta permanece.
GY 26/03

Ah, ok, mas é confuso quando você faz referência à documentação do C ++. Então, o que você está dizendo é que a especificação não foi implementada corretamente?
Peter Peter

Não. O que estou dizendo é que é indefinido de acordo com a especificação e o uso de indefinido resultará em resultados indefinidos.
GY 26/03

Indefinido em C ++, mas o C # diz que deve ter o mesmo valor após a operação , não? Isso não é o mesmo que indefinido (mas eu concordo que você não deve usá-lo, veja meu aviso, eu estava apenas tentando entender o que está acontecendo).
Peter Peter

4

O operador ++ após a variável faz com que seja um incremento do postfix. O incremento acontece depois de tudo o mais na declaração, adição e atribuição. Se, em vez disso, você colocar o ++ antes da variável, isso aconteceria antes que o valor de i fosse avaliado e lhe desse a resposta esperada.


2
O ++que não acontece após a +=declaração, isso acontece durante a execução da +=declaração. É por isso que os efeitos da ++substituição são substituídos pelo +=.
DTB

Usando ++, na verdade, resulta em 1, e não em 2 (minha originalmente 'resposta esperada').
24412 Peter Peter

Parece que a atribuição += substitui a modificação devido ao pré ou pós-incremento na expressão.
9189 Steven St Luan

4

As etapas do cálculo são:

  1. int i=0 // Inicializado para 0
  2. i+=i++ //Equação
  3. i=i+i++ // depois de simplificar a equação pelo compilador
  4. i=0+i++ // substituo valor
  5. i=0+0 // i ++ é 0, conforme explicado abaixo
  6. i=0 // Resultado final i = 0

Aqui, inicialmente o valor ié 0. WKT, i++nada mais é: primeiro use o ivalor e depois aumente o ivalor em 1. Portanto, ele usa o ivalor 0, enquanto calcula i++e depois o incrementa em 1. Portanto, resulta em um valor de 0.


3

Existem duas opções:

A primeira opção: se o compilador ler a instrução da seguinte maneira,

i++;
i+=i;

então o resultado é 2.

Para

else if
i+=0;
i++;

o resultado é 1.


5
Nenhum dos quais é o real resultado .
Steven Lu

3

Tenha muito cuidado: leia o FAQ C : o que você está tentando fazer (misturar atribuição e ++da mesma variável) não é apenas não especificado, mas também é indefinido (o que significa que o compilador pode fazer qualquer coisa ao avaliar! resultados "razoáveis").

Por favor, leia a seção 3 . Vale a pena ler toda a seção! Especialmente 3.9, o que explica a implicação de não especificado. A Seção 3.3 fornece um resumo rápido do que você pode ou não fazer com "i ++" e similares.

Dependendo dos componentes internos dos compiladores, você pode obter 0, 2 ou 1 ou qualquer outra coisa! E como não está definido, não há problema em fazê-lo.


oops, c # ... fui expulso pelo "gcc" que alguns passaram para desmontar o código.
amigos estão dizendo sobre olivier

1
Eu também senti falta de C #, mas gostei da resposta de qualquer maneira.
Iain Collins

1
@Iain: obrigado, eu também acredito que valeu a pena manter a resposta disponível, muitas pessoas não sabem sobre isso (ou sobre essa grande faq, do melhor momento da Usenet, onde a maioria das pessoas com conhecimento sobre um assunto estava indo para o mesmo local para atualizá-lo)
Olivier Dulac 23/11

3

Há um excelente raciocínio nas respostas acima. Acabei de fazer um pequeno teste e quero compartilhar com você

int i = 0;
i+ = i++;

Aqui o resultado i está mostrando 0 resultado. Agora considere os casos abaixo:

Caso 1:

i = i++ + i; //Answer 1

anteriormente, eu pensei que o código acima se assemelha a isso, então, à primeira vista, a resposta é 1, e realmente a resposta de i para esta é 1.

Caso 2:

i = i + i++; //Answer 0 this resembles the question code.

aqui o operador de incremento não vem no caminho da execução, diferente do caso anterior em que o i ++ tem a chance de executar antes da adição.

Espero que isso ajude um pouco. obrigado


2

Na esperança de responder a isso de um tipo de perspectiva da programação C 101.

Parece-me que está acontecendo nesta ordem:

  1. ié avaliado como 0, resultando na i = 0 + 0operação de incremento i++"enfileirada", mas a atribuição de 0 a iainda não aconteceu.
  2. O incremento i++ocorre
  3. A atribuição i = 0acima acontece, substituindo efetivamente qualquer coisa que o número 2 (o pós-incremento) teria feito.

Agora, o número 2 pode nunca realmente acontecer (provavelmente não acontece?) Porque o compilador provavelmente percebe que não servirá a nenhum propósito, mas isso pode depender do compilador. De qualquer forma, outras respostas mais bem informadas mostraram que o resultado está correto e está em conformidade com o padrão C #, mas não está definido o que acontece aqui para C / C ++.

Como e por que está além da minha experiência, mas o fato de a tarefa do lado direito avaliada anteriormente ocorrer após o pós-incremento é provavelmente o que é confuso aqui.

Além disso, você não esperaria que o resultado seja 2 independentemente menos que você fez ++iem vez de i++eu acredito.


1
A versão pré-incremento produz um resultado 2com C ++: ideone.com/8dH8tf
Steven Lu

Isso faz sentido. Mas o pré-incremento é uma situação marginalmente menos complicada do que o pós-incremento.
gkimsey

2

Simplificando,

i ++, adicionará 1 a "i" após a conclusão do operador "+ =".

O que você deseja é ++ i, para que ele adicione 1 ao "i" antes que o operador "+ =" seja executado.


0
i=0

i+=i

i=i+1

i=0;

Em seguida, o 1 é adicionado a i .

i + = i ++

Portanto, antes de adicionar 1 a i, iassumimos o valor 0. Somente se adicionarmos 1 antes, iobtenha o valor 0.

i+=++i

i=2

-4

A resposta é iserá1 .

Vamos dar uma olhada em como:

Inicialmente i=0; .

Então, enquanto calculamos de i +=i++;acordo com o valor de, teremos algo como 0 +=0++;: portanto, de acordo com a precedência do operador 0+=0, o primeiro será executado e o resultado será0 .

Em seguida, o operador de incremento será aplicado como 0++, como 0+1e o valor de iserá 1.


3
Esta resposta está errada. Você não terá 1 porque quando você faz 0 += 0++;atribuição é depois incremento ++, mas com o valor de i interpretado antes de ++(porque é um operador post.
PhoneixS

2
Desculpe, mas isso está incorreto. Leia a minha pergunta e você vai ver que eu digo o resultado é 0. Se você executar o código, você verá que é efetivamente 0.
Peter
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.