¿Cómo funcionan las operaciones Prefix (++ x) y Postfix (x ++)?

¿Puede alguien decirme cómo funcionan realmente los operadores de prefijo / postfijo? He estado buscando mucho en línea, pero no he encontrado nada.

De lo que puedo decir precede los primeros incrementos, luego realiza la operación y luego los asigna.
Postfix haría la operación primero, luego asigna y luego incrementa.

Pero estoy teniendo un problema con mi código:

int x, y; x = 1; y = x + x++; // (After operation y = 2)(x=2) 

Sin embargo cuando lo hago:

 y = x++ + x; // (After operation y = 3)(x=2) 

No estoy seguro de por qué estas operaciones serían diferentes. Tengo dos preguntas:

  • ¿Podrías explicar la diferencia?

  • ¿Cómo se aplica esto al otro prefijo del operador?

    • En C #, los operandos de + se evalúan en orden de izquierda a derecha.
    • En C y C ++, el orden de evaluación para los operandos de + no está especificado.

    Para C # tus ejemplos funcionan de la siguiente manera:

      y = x + x++; ^ x is 1 ^ x is increased to 2, but the postfix increment returns the old value (1) y = 2 y = x++ + x; ^ x becomes 2, but postfix increment returns the old value (1) ^ x is now 2 here y = 3 

    Esta pregunta se hace una cantidad justa. Tenga en cuenta que cada vez que alguien hace esta pregunta, muchas personas publican respuestas incorrectas. Muchas personas tienen ideas incorrectas sobre el funcionamiento de estos operadores, incluidas las personas que escriben libros de progtwigción y, por lo tanto, les enseñan falsedades a otras personas. Lea las otras respuestas aquí con mucho cuidado.

    Para un correcto análisis del comportamiento C #, ver:

    ¿Cuál es la diferencia entre i ++ y ++ i?

    Para C ++ cualquier comportamiento es correcto, en aquellos casos en los que observas un efecto secundario. C ++ no define cuándo el efecto secundario del incremento es visible. Cualquiera de los dos comstackdores puede hacerlo de manera diferente.

    Una buena regla a seguir es no confiar en el orden en que ocurren los efectos secundarios en ningún idioma, pero ciertamente no se debe confiar en C ++, porque no es confiable.

    Para ver su caso específico:

     int x, y; x = 1; y = x + x++; 

    Usted informa que xey son ambos 2. Eso es correcto en C #. En C #, el comportamiento correcto es:

    • evaluar y como una variable
    • evalúa x como un valor – es 1
    • evaluar x ++ como un valor. Esto evalúa x como una variable, luego toma su valor original que es 1, luego incrementa ese valor, que es 2, luego asigna 2 a x y luego da como resultado el valor original, que es 1.
    • evalúa 1 + 1, que es 2
    • asignar 2 a y.

    Entonces xey son ambos 2 en C #.

    C ++ puede hacer lo mismo, pero está permitido evaluar la adición en orden de derecha a izquierda. Es decir, está permitido hacer:

    • evaluar x ++ como un valor. Esto evalúa x como una variable, luego toma su valor original que es 1, luego incrementa ese valor, que es 2, luego asigna 2 a x y luego da como resultado el valor original, que es 1.
    • evalúa x como un valor – es 2
    • evalúa 1 + 2, que es 3
    • evaluar y como una variable
    • asignar 3 a y.

    C ++ también tiene permitido hacer esto:

    • evaluar x ++ como un valor. Esto evalúa x como una variable, luego toma su valor original que es 1, luego incrementa ese valor, que es 2 … falta aquí el paso … y luego da como resultado el valor original, que es 1.
    • evalúa x como un valor – es 1
    • evalúa 1 + 1, que es 2
    • asigna 2 a x – el paso que faltaba antes.
    • evaluar y como una variable
    • asignar 2 a y.

    Entonces en C ++, puede obtener y como 3 o 2, dependiendo del capricho del escritor del comstackdor. En C # siempre obtienes que y es 2. En C ++, la asignación del incremento puede ocurrir en cualquier momento , siempre que ocurra. En C #, la asignación del incremento debe ocurrir después de que se compute el valor incrementado y antes de que se use el valor original. (Cuando se observa desde el hilo de ejecución, si está tratando de observar esto desde otro hilo o subprocesos, todas las apuestas están desactivadas).

    En tu segundo ejemplo:

     y = x++ + x; 

    En C # el comportamiento requerido es:

    • evaluar y como una variable
    • evaluar x ++ como un valor. Esto evalúa x como una variable, luego toma su valor original que es 1, luego incrementa ese valor, que es 2, luego asigna 2 a x y luego da como resultado el valor original, que es 1.
    • evalúa x como un valor – es 2
    • evalúa 1 + 2, que es 3
    • asignar 3 a y.

    Entonces, la respuesta correcta en C # es que y es 3 y x es 2.

    De nuevo, C ++ puede hacer estos pasos en cualquier orden. C ++ puede hacer:

    • evalúa x como un valor – es 1
    • evaluar x ++ como un valor. Esto evalúa x como una variable, luego toma su valor original que es 1, luego incrementa ese valor, que es 2, luego asigna 2 a x y luego da como resultado el valor original, que es 1.
    • evalúa 1 + 1, que es 2
    • evaluar y como una variable
    • asignar 2 a y.

    De nuevo, en C ++ la respuesta correcta es que y es 2 o 3, dependiendo del capricho del escritor del comstackdor. En C #, la respuesta correcta es que y es 3.

    En ambos casos, el incremento se aplicó después de que se usó la x. En el primero, se evaluó de la siguiente manera: y = 1 + 1 (incrementado a 2)

    en el segundo

    y = 1 (incrementado a 2) + 2.

    Es por eso que tienes diferentes respuestas.

    En C y C ++:
    La salida no está especificada .

    Referencia – Estándar C ++ 03:

    Sección 5: Expresiones, Párr. 4:

    excepto donde se indique [por ejemplo, reglas especiales para && y ||], el orden de evaluación de operandos de operadores individuales y las subexpresiones de expresiones individuales, y el orden en que se producen los efectos secundarios, no se especifica.

    En C99, sección 6.5.

    “La agrupación de operadores y operandos se indica mediante la syntax.72) Excepto como se especifica más adelante (para los operadores de función-llamada (), &&, ||,?: Y coma), el orden de evaluación de las subexpresiones y el orden en el que tienen lugar los efectos secundarios no están especificados “.

    Las expresiones x++ y ++x tienen un resultado (o valor) y un efecto secundario .

    Si restringimos nuestra discusión a los operandos de tipo integral, el resultado de x++ es cualquiera que sea el valor actual de x . El efecto secundario es incrementar x en 1. Por lo tanto, dado el código

     x = 0; y = x++; 

    el resultado será x == 1 e y == 0 (suponiendo que y son tipos integrales).

    Para ++x , el resultado es 1 más el valor actual de x . El efecto secundario es incrementar x en 1. Por lo tanto, dado el código

     x = 0; y = ++x; 

    el resultado será x == y == 1.

    Lo que distingue a C y C ++ de C # es cuando se evalúan los operandos y cuando se aplican los efectos secundarios. C # garantiza que los operandos en una expresión siempre se evalúan de izquierda a derecha. C y C ++ solo garantizan la evaluación de izquierda a derecha para && , || , operadores ” ?: , “coma” y “function-call () : para todos los demás operadores, el orden en que se evalúan los operandos no está especificado .

    De forma similar, en C #, los efectos secundarios de x++ y ++x se aplicarán inmediatamente después de que se haya evaluado la expresión, mientras que C y C ++ solo requieren que se aplique el efecto secundario antes del siguiente punto de secuencia .

    Las reglas de evaluación de C # garantizan que las expresiones como x = x++ , a = b++ * b++ y a[i] = i++ están bien definidas, mientras que las definiciones de lenguaje C y C ++ dicen explícitamente que dichas expresiones dan como resultado un comportamiento indefinido (cualquier resultado es posible).

    x + x ++ y x ++ + x son ejemplos de casos patológicos de efectos secundarios de los que no se quiere depender. x ++ y ++ x ambos incrementan x, pero al agregar x el orden de evaluación no está definido – el comstackdor puede elegir qué ‘lado’ evalúa primero.

    Considerar:

     y = x + x++; 

    Ya sea que su comportamiento esté definido o no (no está definido en C y C ++, aparentemente está bien definido en C #), sea lo que sea que intentes hacer, seguramente habrá una mejor manera de expresslo.

    Si está asumiendo una estricta evaluación de izquierda a derecha, lo anterior podría escribirse como:

     y = x * 2; x ++; 

    El significado es claro e inequívoco para cualquier lector que sepa qué = , * y ++ significan, y los mantenedores futuros de su código no tendrán la tentación de perseguirlo.

    O puede escribir x + x o x < < 1 si no confía en el comstackdor para generar un código eficiente, pero tal desconfianza suele estar fuera de lugar.

    Si insistes, incluso podrías escribir:

     y = x++ * 2; 

    Eso es un poco escueto para mi gusto personal, pero sigue siendo inequívoco.

    Si quieres entender el código de otra persona (que es algo que los progtwigdores gastan mucho tiempo), entender las expresiones complicadas puede ser importante. Pero cuando escribe su propio código, la claridad es más importante que guardar las pulsaciones de teclas (o mostrar cuán bien conoce las tablas de precedencia del operador).