2010-10-12 17 views
6
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; 
} 

pensé que & & tiene mayor precedencia que || según esta lógica ++j debería ejecutarse, pero nunca lo hace y el programa genera -2 2 0 1. ¿Que esta pasando aqui? ¿Cuáles son los pasos intermedios?Evaluación de la expresión C

Respuesta

14

&& tiene mayor precedencia que ||, lo que significa que ++i || ++j && ++k análisis sintáctico como ++i || (++j && ++k). Sin embargo, esto no cambia el hecho de que el RHS de || solo se ejecuta si el LHS devuelve 0.

La precedencia no afecta el orden de evaluación.

+1

Te refieres a LHS. – SLaks

+1

@SLaks: Sí, lo hago. Editado – sepp2k

4

C++ utiliza evaluación diferida para los operadores lógicos.
Si escribe a || b, y a es verdadero, b nunca lo evaluará, ya que el resultado será verdadero incluso si b es falso.
De manera similar, a && b no evaluará b si a es falso.

Dado que ++i se evalúa con un valor de verdad, ninguna de las otras expresiones se evalúa.

+0

Y 'm' es 1 porque ...? – sje397

+0

C++ utiliza evaluación diferida ... una declaración demasiado amplia. Por ejemplo, 0 yx siempre es 0 pero x, no obstante, se evalúa. Esta pereza, o, más correctamente, evaluación de cortocircuito se refiere solo a los operadores incorporados && y || (¿y en algún sentido? :) –

+0

@ sje397: Porque la verdad (el resultado de la cláusula '||') es '1'. – SLaks

1

& & y || use la evaluación de cortocircuito, es decir, en la expresión a & & b a se evalúa primero, si es falso, entonces la expresión completa es falsa y b no se evalúa. En a || b si a es verdadero, b no se evalúa. Tenga en cuenta que si sobrecarga & & o || las reglas de cortocircuito ya no se aplicarán. HTH

7

La precedencia no tiene un efecto en el orden de evaluación (excepto cuando sea necesario, algunas sub-expresiones podrían necesitar ser evaluadas antes que otras debido a la precedencia). Por ejemplo, en la expresión simple:

a() + b() + c() * d() 

a pesar de que la multiplicación tiene precedencia sobre Además, el compilador es libre de realizar las llamadas a las funciones en cualquier orden que le gusta, y podría llamar a() o b() antes o después de que se realiza la multiplicación. Obviamente, tiene que evaluar c() y d() antes de realizar la multiplicación. Si estas funciones tienen efectos secundarios (como la modificación y el uso de variables globales), el orden de evaluación indeterminado podría generar resultados inesperados.

Sin embargo, para algunos operadores, la norma prescribe un estricto orden de evaluación. Es esto decir sobre || lógico u operador:

A diferencia del bitwise | operador, || el operador garantiza la evaluación de izquierda a derecha; hay un punto de secuencia después de la evaluación del primer operando. Si el primer operando compara desigual a 0, el segundo operando no se evalúa.

Así que no sólo la || proporcionan una garantía de pedidos, sino que también garantiza que, bajo ciertas condiciones, el segundo operando no será evaluado en absoluto.

(también dice algo similar para el && - excepto que en ese caso el 2do operando no se evalúa si el primero evalúa a 0. Pero en su ejemplo, el || es lo primero).

Otros operadores que proporcionan cierta garantía de pedido incluyen el operador de coma y la llamada de función (lo que garantiza que los argumentos han sido evaluados, pero no el orden en que se han evaluado dichos argumentos).

+1

Buena explicación. Añadiría que hay una buena razón para la evaluación de cortocircuitos: hace que los condicionales sean mucho más fáciles de escribir. Por ejemplo, if (i baz! = MAGIC_NUMBER).Usted sabe que la primera parte (también conocida como guardia) se evalúa primero, por lo que no leerá fuera de la matriz ni eliminará NULL. Sin una orden garantizada, tendrías que anidar dos declaraciones if. En algunos otros idiomas, el orden no está garantizado, por lo que verá declaraciones anidadas si se usan como guardia todo el tiempo. –

1

C hace short-circuiting de expresiones lógicas, por lo que la evaluación de ++i es suficiente para darse cuenta de que m debería ser cierto.

0

¿Estaba usted por casualidad en realidad con ganas de escribir:

m = ++i | ++j & ++k; 

que emite -2 3 1 -1

+0

no, FWIW sé la diferencia entre los operadores bit a bit y otros operadores. – shreyasva

+0

Pensé que sí, así que no estaba tratando de ser presuntuoso :) Estaba dando clases a alguien el otro día que los confundió. –

0

m = i ++ || ++ j & & ++ k;

Desde && tiene mayor precedencia que || por lo que la expresión se interpreta como ++i || (++j && ++k)

|| es cortocircuito y operando mano tan a la derecha del operador || no recibe evaluado porque ++i devuelve un valor distinto de cero.

1
  1. Las fuerzas || operador de izquierda a derecha evaluación, por lo que la expresión ++i está completamente evaluado por primera vez, con un resultado de -2.
  2. El operador || fuerza un punto de secuencia, por lo que se aplica el efecto secundario y i ahora es igual a -2.
  3. El resultado de la expresión ++i no es 0, por lo que la expresión ++j && ++k no se evalúa en absoluto.
  4. Dado que el LHS no es cero, el resultado de toda la expresión ++i || ++j && ++k es 1 (verdadero), que se asigna al m.

Solo para repetir lo que otros han dicho, la precedencia y el orden de evaluación no son lo mismo.

+0

+1 - la única respuesta hasta el momento que responde * todo * a la pregunta. – sje397

Cuestiones relacionadas