2012-06-16 10 views
5

Cuando ejecuta este código, la salida es de 11, 10.Utilizando el post-incremento en los argumentos de funciones

¿Por qué en la tierra sería? ¿Puede alguien darme una explicación de esto que con suerte me iluminará?

Gracias

#include <iostream> 
using namespace std; 

void print(int x, int y) 
{ 
    cout << x << endl; 
    cout << y << endl; 
} 
int main() 
{ 
    int x = 10; 
    print(x, x++); 
} 
+1

consigo un error muy notable/advertencia (-Werror) en GCC 4.7.0: 'error: operación en 'x' puede ser sin definir [-Werror = punto de secuencia] '. Siempre es bueno tener tu nivel de advertencia activado. – chris

+0

@ acidzombie24, veo que editaste mi publicación, específicamente los parámetros de función en de impresión. ¿Cuál fue la razón para eso? Cambiar el segundo parámetro de "x ++" a "x + 1" tipo de derrota el propósito de toda la publicación, ¿no? – ordinary

+0

oh lo siento. Fue un gran descuido. Estaba jugando con un código y olvidé que cambié ++ a +1. Que los números y el formato me molestaban y copié/pegué mi código sobre él. El que tiene el +1 ... oops. Lo cambié de vuelta. (Espero que puedas editar tu propia publicación así que tal vez puedas hacer eso si vuelves a ver un error así) –

Respuesta

11

Los C++ standard estados (A nota en la sección 1.9.16):

Value computations and side effects associated with the different argument expressions are unsequenced.

En otras palabras, es indefinido y/o compilador dependiente de qué orden los argumentos son evaluados antes de su valor se introduce en el función. Por lo tanto, en algunos compiladores (que evalúan primero el argumento de la izquierda) ese código generaría 10, 10 y en otros (que evalúan primero el argumento de la derecha) dará como resultado 11, 10. En general, nunca debes confiar en un comportamiento indefinido.

Para ayudarlo a comprender esto, imagine que cada expresión de argumento se evalúa antes de que la función se llame así (no es que así sea exactamente, es solo una forma fácil de pensar que lo ayudará a comprender el secuenciación):

int arg1 = x;  // This line 
int arg2 = x++;  // And this line can be swapped. 
print(arg1, arg2); 

El estándar C++ dice que las dos expresiones de argumento no se han secuenciado. Entonces, si escribimos las expresiones del argumento en líneas separadas como esta, su orden no debería ser significativa, porque la norma dice que pueden evaluarse en cualquier orden. Algunos compiladores podrían evaluarlas en el orden anterior, otros podrían intercambiarlos:

int arg2 = x++;  // And this line can be swapped. 
int arg1 = x;  // This line 
print(arg1, arg2); 

Eso hace que sea bastante obvio cómo arg2 puede contener el valor 10, mientras que mantiene el valor arg111.

Siempre debe evitar este comportamiento indefinido en su código.

+0

La primera vez que he visto a alguien realmente vincular a la norma en su respuesta, que no sea para la pregunta de dónde conseguirlo. – chris

+0

¡Gracias, ahora lo entiendo totalmente! Volvería a votar, pero no tengo suficientes puntos de karma o lo que sea. – ordinary

+1

Para que quede claro, esto no es un Comportamiento no definido, sino solo un Comportamiento no especificado. Ambos son claramente diferentes. –

4

x ++ es un parámetro de función y pueden ser evaluados en un orden no especificado que significa que el comportamiento es indefinido y no portátil (o legal).

+0

En realidad, esto no es solo un Comportamiento No Especificado, pero lo más importante es que es un Comportamiento Indefinido. Comprueba mi respuesta. –

0

Creo que esto tiene que ver con la pila de llamadas de función donde el último argumento entra primero. Entonces x ++ es su yyx es la x local en la impresión().

6

En su conjunto la declaración:

print(x, x++); 

da como resultado un comportamiento indefinido . Una vez que un programa tiene un comportamiento indefinido deja de ser un programa válido de C++ y, literalmente, cualquier comportamiento es posible. Por lo tanto, no tiene sentido encontrar un razonamiento para dicho programa.


Why is this Undefined Behavior?

Permite evaluar el programa paso a paso hasta el punto en el que podemos probar fuera de toda duda que causa comportamiento indefinido.

El orden de evaluación de argumentos a una función es no especificados[Ref 1].

no especificado significa que se permite una implementación para implementar esta funcionalidad particular en lo que se desea y no se requiere para documentar los detalles al respecto.

La aplicación de la regla anterior a su función de llamada:

print(x, x++); 

Una implementación podría evaluar esto como:

  • izquierda a derecha o
  • derecha a izquierda o
  • Cualquier orden mágico (en caso de más de dos argumentos de función)

En resumen, no puede confiar en que una implementación siga un orden específico porque no es obligatorio según el estándar de C++.

En C/C++ no puede leer o escribir en una variable más de una vez sin una intervención sequence point[Ref 2] Si usted hace así que resulta en una Indefinido Behavior.Irrespective de si cualquiera de los argumentos se evalúan primero en dicha función, no hay punto de secuencia entre ellos, solo existe un punto de secuencia después de la evaluación de todos los argumentos de función [Ref 3].

En este caso, se accede a x sin un punto de secuencia intermedio y, por lo tanto, da como resultado un Comportamiento indefinido.

En pocas palabras es mejor que escribir ningún código que no invoque tales Undefined Comportamientos porque una vez que lo hace no se puede esperar ningún comportamiento específico de un programa de este tipo.


[Ref 1]C++ 03 Standard §5.2.2.8
Párrafo 8:

[...] The order of evaluation of function arguments is unspecified. [...]


[Ref 2]C + +03 5 Expresiones [expr]:
Para 4:

....
Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.


[Ref 3]C++ 03 1.9 La ejecución del programa [INTRO.ejecución]:
Párrafo 17:

When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all function arguments (if any) which takes place before execution of any expressions or statements in the function body.

Cuestiones relacionadas