Para i = 0, ¿por qué es (i + = i ++) igual a 0?

253

Tome el siguiente código (utilizable como una aplicación de consola):

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

El resultado ies 0. Esperaba 2 (como lo hicieron algunos de mis colegas). Probablemente el compilador crea algún tipo de estructura que resulta eni cero.

La razón por la que esperaba 2 es que, en mi línea de pensamiento, la declaración de la derecha se evaluaría primero, incrementando i con 1. De lo que se agrega a i. Como ya soy 1, agrega 1 a 1. Entonces 1 + 1 = 2. Obviamente, esto no es lo que está sucediendo.

¿Puedes explicar qué hace el compilador o qué sucede en tiempo de ejecución? ¿Por qué el resultado es cero?

Algún tipo de descargo de responsabilidad: estoy absolutamente consciente de que no usará (y probablemente no debería) usar este código. Sé que nunca lo haré. Sin embargo, me parece interesante saber por qué actúa de esa manera y qué está sucediendo exactamente.

Peter
fuente
57
¿No debería ser el resultado esperado 1? i (0) + = i ++ (1) por lo tanto 0 + = 1 = 1
alegación el
11
Funciona como se esperaba
Steve es un D
177
¿Cuántas variaciones de esta pregunta se harán?
mowwwalker
20
La preincrementación incrementará el valor antes de hacer la acción i + = ++ te daré 1
Pierluc SS
21
¿Por qué todos se centran en el pre y postincremento? Lo "extraño" es que el valor de ien el lado izquierdo +=se "almacena en caché" antes de evaluar el lado derecho. Esto es contrario a la intuición, ya que, por ejemplo, requeriría una operación de copia si ifuera un objeto. (Por favor, no me entiendan mal: estoy totalmente de acuerdo en afirmar que 0es la respuesta correcta y que cumple con los estándares.)
JohnB

Respuestas:

425

Esta:

int i = 0;
i += i++

Puede verse como lo hace (lo siguiente es una simplificación excesiva):

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

Lo que realmente sucede es más complicado que eso: eche un vistazo a MSDN, 7.5.9 operadores de incremento y decremento de postfix :

El procesamiento en tiempo de ejecución de una operación de incremento o disminución de postfix de la forma x ++ o x-- consta de los siguientes pasos:

  • Si x se clasifica como una variable:

    • x se evalúa para producir la variable.
    • El valor de x se guarda.
    • El operador seleccionado se invoca con el valor guardado de x como argumento.
    • El valor devuelto por el operador se almacena en la ubicación dada por la evaluación de x.
    • El valor guardado de x se convierte en el resultado de la operación.

Tenga en cuenta que debido al orden de precedencia , el postfix ++ocurre antes += , pero el resultado termina sin iusarse (ya que se usa el valor anterior de ).


Una descomposición más completa de i += i++las partes que lo componen requiere uno para saber que tanto +=y ++no son atómica (es decir, ninguno de los dos es una sola operación), incluso si se ven como son. La forma en que se implementan implica variables temporales, copias de iantes de que se realicen las operaciones, una para cada operación. (Usaré los nombres iAddy iAssignpara las variables temporales usadas para ++y+= respectivamente).

Entonces, una aproximación más cercana a lo que está sucediendo sería:

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;
Oded
fuente
3
@Oded La ++operación se realiza antes de que se complete la evaluación de la declaración. Entonces +=sobrescribe el valor. ¿Es esto lo que pasó?
Anirudh Ramanathan
66
@Oded realidad su: int i = 0; i = i + 1; (postfix) i = 0; (assignment). Si usó i en otra parte de esa declaración, se evaluaría a 1 en ese momento.
drch
@Cthulhu: esencialmente. La respuesta de dtb entra en detalles.
Oded
66
No compro este. La respuesta de @yoriy es mucho más precisa. Por un lado, en su respuesta, usted dice que la última línea sería i+1mientras debería ser i=i+1. ¿No es eso lo que i++es?
recluze
3
La primera parte de la respuesta es redundante. Su último ejemplo de código podría haberlo hecho en mi humilde opinión. +1 sin embargo.
corazza
194

Desmontaje del código de ejecución:

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

Se compila con el mismo código que el siguiente 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;

Desmontaje del segundo código (solo para demostrar que son iguales)

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 ventana de desmontaje

La mayoría de las personas no saben, o incluso no recuerdan, que pueden ver el código final de ensamblaje en memoria, usando la ventana Desmontaje de Visual Studio . Muestra el código de máquina que se está ejecutando, no es CIL.

Use esto mientras depura:

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

Entonces, ¿qué está pasando con postfix ++?

El postfix ++ dice que nos gustaría incrementar el valor del operando después de la evaluación ... que todo el mundo sabe ... lo que confunde un poco es el significado de "después de la evaluación" .

Entonces, ¿qué significa "después de la evaluación" significa:

  • otros usos del operando, en la misma línea de código deben verse afectados:
    • a = i++ + i el segundo me afecta el incremento
    • Func(i++, i) el segundo me afecta
  • otros usos en la misma línea respetan operador de cortocircuito como ||y &&:
    • (false && i++ != i) || i == 0 el tercero no se ve afectado por i ++ porque no se evalúa

Entonces, ¿cuál es el significado de i += i++;:?

Es lo mismo que i = i + i++;

El orden de evaluación es:

  1. Almacenar i + i (es decir, 0 + 0)
  2. Incremento i (me convierto en 1)
  3. Asigne el valor del paso 1 a i (i se convierte en 0)

No es que se descarte el incremento.

¿Cuál es el significado de i = i++ + i;:?

Esto no es lo mismo que el ejemplo anterior. El tercero ise ve afectado por el incremento.

El orden de evaluación es:

  1. Tienda i (eso es 0)
  2. Incremento i (me convierto en 1)
  3. Almacene el valor del paso 1 + i (es decir, 0 + 1)
  4. Asigne el valor del paso 3 a i (i se convierte en 1)
Miguel angelo
fuente
22
+ 1 ++ - para una disección hardcore pura. Chuck Norris estaría orgulloso :) Supongo que
supones
19
C # tiene un orden de evaluación bien definido para la expresión, y el código objeto simplemente implementa ese orden. La salida del código de máquina no es el motivo o la explicación del pedido de evaluación.
Kaz
8
El código de máquina facilita la comprensión de cómo se implementa el orden de evaluación IMO.
Kevin
55
@StuartLC Veo lo que hiciste allí. Sin embargo, lástima de ese voto descartado.
Steffan Donal
2
a++ + ano es lo mismo que a + a++porque esto ya no es pura matemática. La ley de conmutatividad en álgebra no tiene en cuenta la posibilidad de que las variables cambien de valor a la mitad de una expresión. Las matemáticas solo se asignan perfectamente a la programación cuando la programación es funcional. Y ni siquiera entonces, debido a limitaciones de representación. Por ejemplo, los números de coma flotante a veces se comportan como reales y otras no. Incluso sin efectos secundarios, las leyes de conmutatividad y asociatividad que se aplican a los números reales en matemáticas se rompen sobre los números de coma flotante.
Kaz el
61
int i = 0;
i += i++;

se evalúa de la siguiente manera:

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

ies decir, se cambia dos veces: una por la i++expresión y otra por la +=declaración.

Pero los operandos de la +=declaración son

  • el valor iantes de la evaluación de i++(lado izquierdo de +=) y
  • el valor iantes de la evaluación de i++(lado derecho de +=).
dtb
fuente
Ah, esta es una explicación fantástica. Me recuerda cuando trabajé en una calculadora basada en pila usando notación de pulido inverso.
Nathan
36

Primero, i++devuelve 0. Luego ise incrementa en 1. Por último, ise establece en el valor inicial, ique es 0 más el valor i++devuelto, que también es cero. 0 + 0 = 0.

Jong
fuente
2
Pero no lo es i += i++;, i = i++;por lo que i++se agrega el valor de (0) iy no " ise establece en el valor i++devuelto". Ahora la pregunta es, cuando se agrega el valor i++devuelto i, ¿ iserá el valor incrementado o el valor no incrementado? La respuesta, mi amigo, está escrita en las especificaciones.
Daniel Fischer el
Es cierto, lo arreglaré. Pero de todos modos desde el i = 0principio, i += somethinges equivalente a lo i = 0 + somethingque es i = something.
Jong
32

Esto es simplemente de izquierda a derecha, evaluación ascendente del árbol de sintaxis abstracta. Conceptualmente, el árbol de la expresión se camina de arriba hacia abajo, pero la evaluación se desarrolla a medida que la recursión vuelve a subir al árbol desde la parte inferior.

// source code
i += i++;

// abstract syntax tree

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

La evaluación comienza considerando el nodo raíz +=. Ese es el componente principal de la expresión. El operando izquierdo de +=debe evaluarse para determinar el lugar donde almacenamos la variable y obtener el valor anterior que es cero. A continuación, se debe evaluar el lado derecho.

El lado derecho es un ++operador de incremento posterior . Tiene un operando, ique se evalúa como una fuente de un valor y como un lugar donde se debe almacenar un valor. El operador evalúa i, encuentra 0y, en consecuencia, almacena un 1en esa ubicación. Devuelve el valor anterior,0 , de acuerdo con su semántica de devolver el valor anterior.

Ahora el control vuelve al +=operador. Ahora tiene toda la información para completar su operación. Conoce el lugar donde almacenar el resultado (la ubicación de almacenamiento de i), así como el valor anterior, y tiene el valor agregado al valor anterior, a saber 0. Entonces, itermina con cero.

Al igual que Java, C # ha desinfectado un aspecto muy estúpido del lenguaje C al fijar el orden de evaluación. De izquierda a derecha, de abajo hacia arriba: el orden más obvio que los codificadores pueden esperar.

Kaz
fuente
+1: Estoy de acuerdo con usted, excepto en que cada codificador espera que ... esperaba que fuera lo mismo que esto: SetSum(ref i, Inc(ref i))con int SetSum(ref int a, int b) { return a += b; }y int Inc(ref int a) { return a++; }... por supuesto, ya no espero eso.
Miguel Angelo
Además, ¡ lo que esperaba es inconsistente! No sería igual a Set(ref i, Sum(i, Inc(ref i)))con int Set(ref int a, int b) { return a = b; }y int Sum(int a, int b) { return a + b; }.
Miguel Angelo
Gracias; Usted insinúa un defecto / incompleto en mi respuesta que tengo que arreglar.
Kaz
El problema SetSumes que no evalúa el operando izquierdo i, sino que solo toma su dirección, por lo que no es equivalente a una evaluación completa de izquierda a derecha del operando. Necesitas algo como eso SetSum(ref i, i, PostInc(ref i)). El segundo argumento de SetSumes el valor a agregar, donde solo usamos ipara especificar el valor anterior de i. SetSumes justo int SetSum(ref int dest, int a, int b) { return dest = a + b; }.
Kaz el
La confusión ocurre (al menos para mí) con el operador + =, porque el operador de asignación tiene una evaluación de derecha a izquierda (por ejemplo, a = b = c = d) ... así que uno puede imaginar que + = sigue la misma regla, como una operación atómica (como hice con mi método SetSum) ... pero lo que sucede de hecho es que C # se traduce a += ben a = a + b... mostrando que el operador + = no es atómico ... es solo azúcar sintáctico.
Miguel Angelo
30

Porque i++primero devuelve el valor, luego lo incrementa. Pero después de que se establece en 1, lo vuelve a establecer en 0.

Yuriy Faktorovich
fuente
17

El método de incremento posterior se parece a esto

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

Entonces, básicamente, cuando llamas i++, ies incremental, pero el valor original se devuelve en tu caso, se devuelve 0.

Ash Burlaczenko
fuente
12

Respuesta simple

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;
Praveen Kumar Purushothaman
fuente
12

i ++ significa: devolver el valor de i ENTONCES incrementarlo.

i + = i ++ significa: Tome el valor actual de i. Agregue el resultado de i ++.

Ahora, agreguemos i = 0 como condición inicial. i + = i ++ ahora se evalúa así:

  1. ¿Cuál es el valor actual de i? Es 0. Almacénelo para que podamos agregarle el resultado de i ++.
  2. Evaluar i ++ (evalúa a 0 porque ese es el valor actual de i)
  3. Cargue el valor almacenado y agregue el resultado del paso 2. (agregue 0 a 0)

Nota: Al final del paso 2, el valor de i es en realidad 1. Sin embargo, en el paso 3, lo descarta cargando el valor de i antes de que se incremente.

A diferencia de i ++, ++ i devuelve el valor incrementado.

Por lo tanto, i + = ++ te daría 1.

Carl
fuente
Es ayuda completa
sonsha
11

El operador de incremento posterior al arreglo ++, le da a la variable un valor en la expresión y luego realiza el incremento que asignó, devolvió el valor cero (0) inuevamente que sobrescribe el incremento (1) , por lo que está obteniendo cero. Puede leer más sobre el operador de incremento en ++ Operador (MSDN).

Adil
fuente
8

i += i++;será igual a cero, porque lo hace ++después.

i += ++i; lo haré antes

Wes Cossick
fuente
44
Si lo hace ++después, esperaría que el resultado sea 1.
comecme
8

Qué está haciendo C # y el "por qué" de la confusión

También esperaba que el valor fuera 1 ... pero algunas exploraciones al respecto aclararon algunos puntos.

Cosider los siguientes métodos:

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

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

Esperaba que i += i++fuera lo mismo que SetSum(ref i, Inc(ref i)). El valor de i después de esta declaración es 1 :

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

Pero luego llegué a otra conclusión ... en i += i++realidad es lo mismo que i = i + i++... así que he creado otro ejemplo similar, usando estas funciones:

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

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

Después de llamar a esto, Set(ref i, Sum(i, Inc(ref i)))el valor de i es 0 :

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

Esto no solo explica lo que C # está haciendo ... sino también por qué mucha gente se confundió con él ... incluyéndome a mí.

Miguel angelo
fuente
2
Agregue esto a su respuesta original, no agrega ningún beneficio tenerlo como una respuesta separada.
casperOne
2
Hice esto para no contaminar la otra respuesta, ya que se trata del código descompilado ... mientras que en este, probé un enfoque diferente para explicar las cosas. ¿Qué piensas? ¿Debo editar la otra respuesta y agregar esta? Tal vez, anteponga este ... ¡no lo sé! Gracias por las sugerencias!
Miguel Angelo
7

Una buena mnemónica que siempre recuerdo sobre esto es la siguiente:

Si ++está detrás de la expresión, devuelve el valor que era antes . Entonces el siguiente código

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

es 1, porque aera 1 antes de que fuera incrementado por la ++situación posterior a . La gente llama a este mensaje notación solución. También hay una notación previa , donde las cosas son exactamente lo opuesto: si ++está antes , la expresión devuelve el valor que está después de la operación:

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

b Hay dos aquí.

Entonces, para su código, esto significa

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

i++devuelve 0 (como se describió anteriormente), entonces 0 + 0 = 0.

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

Scott Meyers describe la diferencia entre esas dos notaciones en "Programación efectiva de C ++". Internamente, i++(postfix) recuerda el valor iera, y llama al prefijo de notación ( ++i) y devuelve el valor antiguo, i. Es por esto que se debe utilizar Allways ++ien forbucles (aunque creo que todos los compiladores modernos están traduciendo i++a ++ien forbucles).

Carsten
fuente
1
Lo probé int i = 0; i += (++i)y iestá configurado en uno en lugar de dos. Tiene sentido para mí también, ya que el uso del prefijo en lugar de la de sufijo no cambia el hecho de que, si se escribe i += (++i)a i = i + (++i), el iresultado se calcula antes ++i, dando como resultado i = 0 + (++i)en última instancia i = 0 + 1.
Wutz
6

La única respuesta correcta a su pregunta es: porque no está definida.

Ok, antes de que todos me quemen ...

Todos respondieron por qué i+=i++está bien y es lógico dar como resultado i=0.

Tuve la tentación de rechazar cada una de sus respuestas, pero la reputación que calculé sería demasiado alta.

¿Por qué estoy tan enojado con ustedes? no por lo que explican sus respuestas ...
Quiero decir, cada respuesta que leí había hecho un esfuerzo notable para explicar lo imposible, ¡Aplausos!

¿Pero cuál es el resultado? ¿Es un resultado intuitivo? ¿Es un resultado aceptable?

Cada uno de ustedes vio al "rey desnudo" y de alguna manera lo aceptó como un rey racional.

¡Todos ustedes están EQUIVOCADOS!

i+=i++;El resultado 0es indefinido.

un error en el mecanismo de evaluación del lenguaje si lo desea ... ¡o incluso peor! Un error en el diseño.

quieres una prueba? por supuesto que quieres!

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

Ahora esto ... ¡es un resultado intuitivo! porque primero evaluamos lo tasignamos con un valor y solo después de la evaluación y la asignación tuvimos la operación posterior, racional, ¿no?

¿es racional que: i=i++y i=iproduzca el mismo resultado i?

mientras t=i++y t=itienen diferentes resultados para i.

La operación posterior es algo que debería ocurrir después de la evaluación de la declaración.
Por lo tanto:

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

Debería ser lo mismo si escribimos:

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

y por lo tanto lo mismo que:

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

y por lo tanto lo mismo que:

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

Cualquier resultado que no 1indique un error en el cumplidor o un error en el diseño del lenguaje si vamos con un pensamiento racional, sin embargo, MSDN y muchas otras fuentes nos dicen "¡Oye, esto no está definido!"

Ahora, antes de continuar, incluso este conjunto de ejemplos que di no es compatible ni reconocido por nadie. Sin embargo, esto es lo que de acuerdo con la forma intuitiva y racional debería haber sido el resultado.

¡El codificador no debe saber cómo se está escribiendo o traduciendo la asamblea!

Si está escrito de una manera que no respetará las definiciones del lenguaje, ¡es un error!

Y para terminar, copié esto de Wikipedia, operadores de incremento y decremento :
dado que el operador de incremento / decremento modifica su operando, el uso de dicho operando más de una vez dentro de la misma expresión puede producir resultados indefinidos . Por ejemplo, en expresiones como x - ++ x, no está claro en qué secuencia se deben realizar los operadores de resta e incremento. Situaciones como esta empeoran aún más cuando el compilador aplica optimizaciones, lo que podría resultar en que el orden de ejecución de las operaciones sea diferente de lo que pretendía el programador.

Y por lo tanto.

¡La respuesta correcta es que esto NO DEBE SER USADO! (ya que no está definido!)

Sí ... - Tiene resultados impredecibles incluso si el cumplidor de C # está intentando normalizarlo de alguna manera.

No encontré ninguna documentación de C # que describa el comportamiento que todos ustedes documentaron como un comportamiento normal o bien definido del lenguaje. ¡Lo que encontré es exactamente lo contrario!

[ copiado de la documentación de MSDN para operadores de incremento y disminución de Postfix: ++ y - ]

Cuando se aplica un operador postfix a un argumento de función, no se garantiza que el valor del argumento se incremente o disminuya antes de pasarlo a la función. Consulte la sección 1.9.17 en el estándar C ++ para obtener más información.

Note esas palabras no garantizadas ...

Perdóname si esa respuesta parece arrogante: no soy una persona arrogante. Solo considero que miles de personas vienen aquí para aprender y las respuestas que leo los engañarán y dañarán su lógica y comprensión del tema.

GY
fuente
No estoy seguro de estar siguiendo al 100%, pero hace referencia a la documentación de C ++, pero mi pregunta era sobre C #. La documentación sobre eso está aquí .
Peter
Me refería a C # en mi respuesta. Desde el enlace que proporcionó: El resultado de x ++ o x-- es el valor de x antes de la operación, mientras que el resultado de ++ x o --x es el valor de x después de la operación. En cualquier caso, x tiene el mismo valor después de la operación. muestra claramente que este no es el caso cuando se realiza la prueba ... porque i=++iproporcionará resultados diferentes de i=i++. Por lo tanto, mi respuesta se mantiene.
GY
Ajá, está bien, pero es confuso ya que hace referencia a la documentación de C ++. Entonces, ¿lo que estás diciendo es que la especificación no se ha implementado correctamente?
Peter
No. lo que digo es que está indefinido de acuerdo con la especificación, y el uso de indefinido terminará en resultados indefinidos.
GY
Indefinido en C ++, pero C # dice que debería ser el mismo valor después de la operación , ¿no? Eso no es lo mismo que indefinido (pero estoy de acuerdo en que no debe usarlo, vea mi descargo de responsabilidad, solo estaba tratando de entender qué está pasando).
Peter
4

El operador ++ después de la variable la convierte en un incremento de postfix. El incremento ocurre después de todo lo demás en la declaración, la suma y la asignación. Si, en cambio, coloca el ++ antes de la variable, sucederá antes de que se evalúe el valor de i, y le dará la respuesta esperada.

KeithS
fuente
2
El ++no sucede después de la +=declaración, sucede durante la ejecución de la +=declaración. Es por eso que los efectos de ++obtener anulación por el +=.
dtb
El uso de ++ i en realidad resulta en 1, no en 2 (mi originalmente 'respuesta esperada').
Peter
Parece que la asignación += sobrescribe la modificación debido al incremento previo o posterior en la expresión.
Steven Lu
4

Los pasos en el cálculo son:

  1. int i=0 // Inicializado a 0
  2. i+=i++ //Ecuación
  3. i=i+i++ // después de simplificar la ecuación por compilador
  4. i=0+i++ // i valor de sustitución
  5. i=0+0 // i ++ es 0 como se explica a continuación
  6. i=0 // Resultado final i = 0

Aquí, inicialmente el valor de ies 0. WKT, i++no es más que: primero use el ivalor y luego incremente el ivalor en 1. Entonces usa el ivalor, 0, mientras calcula i++y luego lo incrementa en 1. Entonces resulta en un valor de 0.

Suresh M
fuente
3

Hay dos opciones:

La primera opción: si el compilador lee la declaración de la siguiente manera,

i++;
i+=i;

entonces el resultado es 2.

por

else if
i+=0;
i++;

El resultado es 1.

NEO
fuente
55
Ninguno de los cuales es el resultado real .
Steven Lu
3

Tenga mucho cuidado: lea las preguntas frecuentes de C : lo que está tratando de hacer (mezcla de asignación y ++de la misma variable) no solo no está especificado, sino que también está indefinido (lo que significa que el compilador puede hacer cualquier cosa al evaluar, no solo dar resultados "razonables").

Por favor lea la sección 3 . ¡Vale la pena leer toda la sección! Especialmente 3.9, lo que explica la implicación de no especificado. La Sección 3.3 le ofrece un resumen rápido de lo que puede y no puede hacer con "i ++" y similares.

Dependiendo de los compiladores internos, puede obtener 0, o 2, o 1, ¡o incluso cualquier otra cosa! Y como no está definido, está bien que lo hagan.

Olivier Dulac
fuente
oops, c # ... Me sorprendió el "gcc" que algunos usaron para desmontar el código.
Olivier Dulac
1
Me perdí que era C # también, pero me gustó la respuesta de todos modos.
Iain Collins el
1
@Iain: gracias, también creo que valió la pena tener la respuesta disponible, muchas personas no saben sobre esto (o sobre esa gran pregunta , desde el mejor momento de Usenet donde la mayoría de las personas con conocimiento en un subjcet iban al mismo lugar para actualizarlo)
Olivier Dulac
3

Hay mucho razonamiento excelente en las respuestas anteriores, acabo de hacer una pequeña prueba y quiero compartir con ustedes

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

Aquí el resultado i muestra 0 resultado. Ahora considere los siguientes casos:

Caso 1:

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

anteriormente pensé que el código anterior se parece a esto, así que a primera vista la respuesta es 1, y realmente la respuesta de i para este es 1.

Caso 2:

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

aquí el operador de incremento no viene en la ruta de ejecución, a diferencia del caso anterior donde i ++ tiene la posibilidad de ejecutarse antes de la adición.

Espero que esto ayude un poco. Gracias

ThomasBecker
fuente
2

Con la esperanza de responder a esto desde una perspectiva de programación C 101.

Me parece que está sucediendo en este orden:

  1. ise evalúa como 0, lo que resulta en i = 0 + 0la operación de incremento i++"en cola", pero la asignación de 0 ai aún no ha sucedido.
  2. El incremento i++ ocurre
  3. La tarea i = 0de arriba sucede, sobrescribiendo efectivamente todo lo que el # 2 (el post-incremento) hubiera hecho.

Ahora, el # 2 puede que nunca suceda (¿probablemente no?) Porque el compilador probablemente se dé cuenta de que no servirá para nada, pero esto podría depender del compilador. De cualquier manera, otras respuestas más informadas han demostrado que el resultado es correcto y se ajusta al estándar C #, pero no está definido qué sucede aquí para C / C ++.

Cómo y por qué está más allá de mi experiencia, pero el hecho de que la asignación del lado derecho evaluada previamente ocurra después del incremento posterior es probablemente lo que es confuso aquí.

Además, no esperaría que el resultado fuera 2, a menos que lo hiciera en ++ilugar de lo i++que creo.

gkimsey
fuente
1
La versión previa al incremento produce un resultado de 2C ++: ideone.com/8dH8tf
Steven Lu
Eso tiene sentido. Pero el pre-incremento es una situación marginalmente menos complicada que el post-incremento.
gkimsey
2

Simplemente pon,

i ++, agregará 1 a "i" después de que el operador "+ =" se haya completado.

Lo que desea es ++ i, para que agregue 1 a "i" antes de que se ejecute el operador "+ =".

seeharper
fuente
0
i=0

i+=i

i=i+1

i=0;

Luego se agrega el 1 a i.

i + = i ++

Entonces, antes de agregar 1 a i, itomó el valor de 0. Solo si agregamos 1 antes, iobtenga el valor 0.

i+=++i

i=2
aprender qué
fuente
-4

La respuesta es iserá 1.

Veamos cómo:

Inicialmente i=0;.

Luego, mientras calculamos de i +=i++;acuerdo con el valor de, tendremos algo así 0 +=0++;, de acuerdo con la precedencia del operador, 0+=0se realizará primero y el resultado será 0.

Luego, el operador de incremento se aplicará como 0++, como 0+1y el valor de iserá 1.

Shivam Sharma
fuente
3
Esta respuesta es incorrecta. No obtendrá 1 porque cuando realiza la 0 += 0++;asignación es después del incremento ++pero con el valor de i interpretado antes de ++(porque es un operador de publicación.)
PhoneixS
2
Lo siento, pero esto es incorrecto. Lea mi pregunta y verá que digo que el resultado es 0. Si ejecuta el código, verá que es efectivamente 0.
Peter