Por favor explique un conflicto aparente entre la precedencia de && y || y el resultado real de una expresión

No entiendo la salida del siguiente progtwig:

#include int main() { int i=-3, j=2, k=0, m; m = ++i || ++j && ++k; printf("%d %d %d %d\n", i, j, k, m); return 0; } 

La salida es -2 2 0 1 lugar de -2 3 1 1 , lo que implica que ++i se evaluó (y provocó que el operador || cortocircuitara su lado derecho) antes de la expresión ++j && ++k que parece contradecir el hecho de que el operador && tiene mayor prioridad que || .

¿Alguien explicaría por qué?

La expresion:

 ++i || ++j && ++k 

Es equivalente a:

 (++i) || ((++j) && (++k)) 

Explicando

  1. ++i se evalúa – (-2) || ((++j) && (++k)) (-2) || ((++j) && (++k)) ;
  2. El || el operador es evaluado – (1) ;

Desde 1 || anything Todo 1 || anything evalúa es verdadero, el operando correcto no es evaluado. Por lo tanto, la precedencia de && no importa aquí. Este cortocircuito está garantizado tanto en C como en C ++ por los estándares relevantes (ver ¿Se obligan los operadores lógicos de cortocircuito? ¿Y el orden de evaluación? ).

Ahora, intenta usar una sub-expresión, como esta:

 (++i || ++j) && ++k 

Lo que equivale a:

 ((++i) || (++j)) && (++k) 

Explicando

  1. ++i se evalúa – ((-2) || (++j)) && (++k) ;
  2. || se evalúa – (1) && (++k)
  3. ++k se evalúa – (1) && (1) ;
  4. Evalúa la verdad;

La salida debe ser algo como:

 Error, line 2: 'm': undefined variable. 

Edición: con eso arreglado, solo el ++i debería ser evaluado. La precedencia no determina (ni siquiera afecta) el orden de evaluación. Precedencia significa que la expresión es equivalente a ++i || (++j && ++k) ++i || (++j && ++k) . Orden de evaluación para || o && siempre es que se evalúa el operando izquierdo, entonces hay un punto de secuencia. Después del punto de secuencia, el operando derecho se evalúa si y solo si es necesario para determinar el resultado final (es decir, el operando derecho de || se evalúa si el operando izquierdo se evalúa a cero; el operando derecho de && se evalúa si el operando izquierdo evaluado a no cero).

En esta expresión, ++i se evalúa, entonces porque es el operando izquierdo de || y evaluado no cero, no se evalúa nada del rest de la expresión.

-2 2 0 1

Perezoso.

 #include  int main() { int i=-3,j=2,k=0; int m=++i||++j&&++k; printf("%d %d %d %d",i,j,k,m); } 

Comstackr, correr y ver por ti mismo.

 gcc tmp.c -o tmp 

A modo de explicación:

 #include  int main() { if (-1) printf ("-1!\n"); else printf ("Not -1.\n"); return 0; } 

Los números negativos no son falsos en C. Siempre compare los valores booleanos con 0 (o FALSE ) o puede ser mordido por if (worked == TRUE) dando falsos negativos.