2012-01-07 24 views
13
int main() { 
    int a = 1; 
    int b = 0; 

    if (a = b || ++a == 2) 
     printf("T: a=%i, b=%i", a, b); 
    else 
     printf("F: a=%i, b=%i", a, b); 

    return 0; 
} 

Echemos un vistazo a este fragmento de código simple. El resultado es: T: a = 1, b = 0¿Por qué se resuelve este código como verdadero?

¿Por qué? (Nota a=b utiliza la asignación de operando, no comparación)

Lo que entiendo aquí, es que cero se asigna a un , a continuación, se incrementa un a 1. 1 no es igual a 2. Así resultado debe de hecho, sea a = 1, b = 0. Pero, ¿por qué se evalúa esta condición como verdadera? Ninguno de (a=b) o (++a == 2) es cierto ... ¿Qué extrañé?

Aquí es otro programa corto que imprime F como se esperaba:

int main() { 
    int a = 1; 
    int b = 0; 

    if (a = b) printf("T"); else printf("F"); 

    return 0; 
} 
+0

Si cambia su || condiciones que probablemente evaluaría como falso como esperabas. –

+0

Oh, lo siento, no es un duplicado. Mi error. –

+0

@ M.Babcock sí, pero ¿por qué no? – Xorty

Respuesta

27

Has confundido a sí mismo con una separación engañosa.

if (a = b || ++a == 2) 

es lo mismo que:

if (a = (b || ((++a) == 2))) 

Este comportamiento se ha hecho sin definir. Aunque hay un punto de secuencia entre la evaluación de b y la evaluación de ((++a) == 2), no hay punto de secuencia entre la asignación implícita a a y la otra escribe a a debido a la asignación explícita =.

+0

Oh, es bueno saberlo. Ahora sí tiene sentido ... –

+1

Para obtener crédito adicional, una vez que se sabe que se supone que debe analizarse de esta manera, ¿está definido, qué con 'a' asignado y autoincrementado? –

+0

@Complicatedseebio: No estoy seguro de lo que está pidiendo que no esté en mi respuesta. –

2

En realidad, misiones tiene la prioridad más baja, por lo que su operador si la declaración es equivalente a:

if (a = (b || (++a == 2))) 

así que usted está asignando un 1, sino también a incrementar en la misma expresión. Creo que eso lleva a un comportamiento indefinido, pero el resultado final es que a es 1 en tu compilador.

0

Si está utilizando GCC u otro compilador con avisos de utilidad similar, activar las advertencias le daría una gran pista sobre lo que ha salido mal aquí. Con gcc -Wall:

advertencia: sugieren paréntesis alrededor de asignación utilizados como valor de verdad

Para ser precisos: el compilador interpreta el código como if (a = (b || ++a == 2)), y la advertencia está sugiriendo que usted lo escribe como if ((a = (b || ++a == 2))) a Haga hincapié en que el código es el correcto, no un error tipográfico para el más común if (a == (b || ++a == 2)).

Por lo que la advertencia requiere un poco de interpretación. Para obtener el efecto deseado, casualmente necesita agregar paréntesis alrededor de una asignación diferente utilizada como valor de verdad, es decir, (a = b). No obstante, la advertencia le dice que algo es desagradable en relación con esta línea de código en particular y que merece un análisis más detallado.

+0

Con GCC reciente, también hay una advertencia sobre el comportamiento indefinido relacionado con el punto de secuencia resultante. Esta es otra gran bandera roja, ya que en el análisis previsto no hay claramente problemas de secuencia de puntos. –

Cuestiones relacionadas