Precedencia de && más ||

Como sé que el operador lógico && tiene mayor prioridad que || . Al ejecutar el código:

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

está dando el resultado:

 1 2 1 1 

lo cual es posible solo cuando ++i || ++j && ++k ++i || ++j && ++k se evalúa así:

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

Pero, de acuerdo con la regla de precedencia del operador, debe evaluarse como:

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

y por lo tanto, el resultado debería ser:

 1 2 1 2 

¿Qué está mal con esto?

NOTA: Según mi entender, creo que un operador de mayor precedencia se evalúa de la siguiente manera ( si se deja asociativo ):
1. Evalúa su expresión izquierda
2. Luego evalúa su expresión correcta (si es necesario)
¿Me equivoco?

Tu dices:

lo cual es posible solo cuando ++i || ++j && ++k ++i || ++j && ++k se evalúa así:

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

Pero, de acuerdo con la regla de precedencia del operador, debe evaluarse como:

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

La primera agrupación es correcta porque la precedencia de && es mayor que la precedencia de || . Entonces, la expresión como un todo evalúa el LHS de || , con el efecto secundario de incrementar i , que se evalúa como verdadero. Eso significa que el RHS de || (la expresión && ) no se evalúa en absoluto porque no es necesaria para determinar la verdad de la expresión general.

Entonces, el comstackdor es correcto; usted no entendió la precedencia de alguna manera.


¿Por qué es la primera agrupación correcta? Según la primera agrupación || tiene una precedencia mayor que && . ¿Qué está pasando mal conmigo?

No entiende la precedencia, parece, o no comprende la interacción de precedencia con el orden de evaluación. La primera agrupación da mayor precedencia a && .

Si tiene a + b * c , donde * tiene una precedencia mayor que + , entonces se evalúa como a + (b * c) , ¿no es así? Cambiar + a || y * a && y las expresiones son isomorfas y la interpretación es similar.

La gran diferencia entre la expresión aritmética y la expresión lógica es que los operandos de la expresión lógica deben evaluarse de izquierda a derecha, pero los operandos de la expresión aritmética no; el comstackdor podría evaluar b * c antes de evaluar a (pero debe evaluar b * c antes de hacer la adición). Por el contrario, en la expresión lógica ( a || b && c ), el comstackdor debe evaluar a antes de evaluar b && c , y cuando resulta ser cierto, no debe evaluar ni c , y mucho menos b && c .

El || Cortocircuitos del operador: si su primer operando se evalúa como verdadero (distinto de cero), no evalúa su segundo operando.

Esto también es cierto para && , no usa su segundo operando si el primero es falso. Esta es una optimización que es posible porque cualquier valor booleano O verdadero es verdadero, y de manera similar, cualquier valor booleano Y falso siempre es falso.


OK, entonces estás confundiendo la precedencia con el orden de evaluación. Nada es contradictorio aquí en absoluto:

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

se agrupa como

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

ya que && tiene mayor precedencia. Pero entonces el LHS de la operación OR es verdadero, por lo que se descarta todo el RHS con su operación AND, no se evalúa.


A su nota en la edición: sí, está equivocado: la precedencia del operador todavía no es lo mismo que el orden de evaluación. Es solo una agrupación.

En primer lugar, como dijiste tú mismo, && tiene mayor precedencia, lo que significa que la agrupación de operandos debería ser

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

¿Por qué está diciendo que “según la precedencia del operador” debería ser (++i || ++j) && (++k) no es claro para mí. Eso solo contradice lo que dijiste tú mismo.

En segundo lugar, la precedencia del operador no tiene absolutamente nada que ver con el orden de evaluación. La precedencia del operador dicta la agrupación entre los operadores y sus operandos (es decir, la precedencia del operador indica qué operando pertenece a qué operador).

Mientras tanto, el orden de evaluación es una historia completamente diferente. O permanece indefinido o definido por un conjunto de reglas completamente diferente. En caso de || y & operadores el orden de la evaluación se define de hecho como de izquierda a derecha (con finalización obligatoria siempre que sea posible).

Entonces, las reglas de precedencia del operador le dicen que la agrupación debe ser

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

Ahora, las reglas de orden de evaluación te dicen que primero evaluamos ++i , luego (si es necesario) evaluamos ++j , luego (si es necesario) evaluamos ++k , luego evaluamos && y finalmente evaluamos || .

Como está malinterpretando la precedencia, intentemos aclararla con un ejemplo matemático. La multiplicación y la división tienen una precedencia más alta que la sum y la resta. Lo que significa que esta expresión:

 a + b * c - d / e 

Puede escribirse así:

 a + (b * c) - (d / e) 

Ya que correctamente && que && tiene mayor prioridad que || , esta expresión:

 i || j && k 

puede escribirse así:

 i || (j && k) 

Puede pensarlo como “la operación con la precedencia más alta se pone entre paréntesis primero”, si eso ayuda.

(Pero la precedencia es diferente de la evaluación : si i soy verdadero, entonces (j && k) nunca será evaluado).