2011-01-08 16 views
12

Considere la siguiente instrucción. ¿Cuál será el valor almacenado en b?uso de operador condicional

int a=1; 
int b = a+=1 ? a+=1 : 10; 

Me sale la respuesta como 4. ¿Alguien puede explicar cómo funciona eso por favor?

+7

Comportamiento indefinido. – GWW

+1

@GWW: ¡No! [....] –

+3

"¿Alguien puede explicar cómo funciona eso por favor?" >> Ciertamente no puedo, pregúntele al programador que lo escribió. Y nunca le pidas que escriba nada de nuevo. :) – Mehrdad

Respuesta

14

Tiene que ver con la precedencia. Si se examina el siguiente código (con el extremo derecho a+=1 cambiado por simplicidad):

#include <iostream> 

int main (void) { 
    int a=1; 
    int b = a+=1 ? 7 : 10; 
    std::cout << b << std::endl; 
    return 0; 
} 

verá que la salida es 8, no 7 o 10.

Eso es debido a que la declaración:

int b = a+=1 ? 7 : 10; 

se interpreta como:

int b = (a += (1 ? 7 : 10)); 

Ahora, aplicándolo a su caso, obtenemos:

int b = (a += (1 ? a += 1 : 10)); 

y, con el fin de ejecución:

  • el más a la derecha a += 1 (desde 1 es verdadero) establece a en 2.
  • el más a la izquierda a += 2 (2 es el resultado del paso anterior) establece a en 4.
  • b = 4 (4 es el resultado del paso anterior).

Solo tenga en cuenta que no necesariamente puede confiar en ese orden de evaluación. Aunque hay un punto de secuencia en ? (por lo que 1 se evalúa por completo antes de continuar), no hay punto de secuencia entre el extremo derecho a += ... y el extremo izquierdo a += .... Y la modificación de una sola variable en dos ocasiones sin un punto de secuencia intermedia es un comportamiento indefinido, que es la razón por gcc -Wall le dará el mensaje de gran utilidad:

warning: operation on ‘a’ may be undefined 

El hecho de que se le da 4 es pura coincidencia. Se podría fácilmente dar 3, 65535 o incluso formatear el disco duro para darle una lección :-) análisis

+0

@shreedhar: Sí, he eliminado mi comentario. Esta respuesta parece ser correcta. –

+0

BTW g ++ me da una advertencia "la operación en' a' puede no estar definida ". –

+1

@Prasoon: Eso es porque 'a + = a + = 1' no está definido. – ephemient

2

Asamblea: Código

int main() 
{ 
    int a=1; 
    int b = a+=1 ? a+=1 : 10; 
    return 0; 
} 

Asamblea generada (utilizando MinGW) para el código anterior es mostrado a continuación. ¡Los comentarios son míos, por supuesto! Lee los comentarios también!

call ___main  //entering into main() 
movl $1, 12(%esp) //int a = 1; means 12(%esp) represents a; 
incl 12(%esp)  //a+=1 ; a becomes 2 
movl 12(%esp), %eax //loading 'a' onto a register(eax); eax becomes 2 
addl %eax, %eax  //adding the register to itself; eax becomes 4 
movl %eax, 12(%esp) //updating 'a' with the value of eax; 'a' becomes 4 
movl 12(%esp), %eax //this step could be optimized away; anyway it loads value of 'a' onto the register(eax); eax becomes 4, in fact even earlier it was 4 too! needless step! 
movl %eax, 8(%esp) //loading the value of eax at another memory location which is 8(%esp); this location represents b; 
movl $0, %eax  //making eax zero! the return value of main()! 
leave    //now main() says, please leave me! 

12(%esp) representan la ubicación de memoria de a, y en un byte distancia 4 de ella, es decir, 8(%esp) representa b. Al final, el valor en ambas ubicaciones de memoria es 4.

Por lo tanto, b = 4. También a = 4.

6

Como se indica en las otras respuestas estos dos fragmentos de código son equivalentes debido a las reglas de la gramática de C++ que determinan cómo las expresiones compuesto debe ser analizada.

int a=1; 
int b = a+=1 ? a+=1 : 10; 

y

int a=1; 
int b = (a += (1 ? (a += 1) : 10)); 

Aunque hay un punto de secuencia en un condicional-expresión es entre la evaluación de la primera expresión (1) y la evaluación de lo que uno de los segundos y tercera expresiones se evalúa (a += 1 en este caso). No hay un punto de secuencia extra explícito después de la evaluación de la segunda o tercera expresión.

Esto significa que a es modificado dos veces en el inicializador para b sin un punto de secuencia intermedia por lo que el código tiene comportamiento indefinido.

+0

Esta es la respuesta correcta. Buena captura Charles. :) +1 –