¿El estándar ANSI mandato de los operadores lógicos que se produzca un cortocircuito, ya sea en C o C ++?
Estoy confundido porque recuerdo el libro de K&R que dice que su código no debería depender de que estas operaciones se cortocircuiten, ya que es posible que no lo hagan. ¿Podría alguien indicar dónde en el estándar se dice que las operaciones lógicas siempre están en cortocircuito? Estoy principalmente interesado en C ++, una respuesta también para C sería genial.
También recuerdo haber leído (no recuerdo dónde) que el orden de evaluación no está estrictamente definido, por lo que su código no debería depender o asumir que las funciones dentro de una expresión se ejecutarían en un orden específico: al final de una declaración, todas las funciones referenciadas habrá sido llamado, pero el compilador tiene libertad para seleccionar el orden más eficiente.
¿El estándar indica el orden de evaluación de esta expresión?
if( functionA() && functionB() && functionC() ) cout<<"Hello world";
fuente
Respuestas:
Sí, se requiere orden de cortocircuito y evaluación para los operadores
||
y&&
en los estándares C y C ++.El estándar C ++ dice (debe haber una cláusula equivalente en el estándar C):
En C ++ hay una trampa adicional: el cortocircuito NO se aplica a los tipos que sobrecargan operadores
||
y&&
.Por lo general, no se recomienda sobrecargar estos operadores en C ++ a menos que tenga un requisito muy específico. Puede hacerlo, pero puede romper el comportamiento esperado en el código de otras personas, especialmente si estos operadores se usan indirectamente a través de plantillas de instanciación con el tipo que sobrecarga a estos operadores.
fuente
La evaluación de cortocircuito y el orden de evaluación es un estándar semántico obligatorio tanto en C como en C ++.
Si no fuera así, un código como este no sería un idioma común
La sección 6.5.13 Operador lógico Y de la especificación C99 (enlace PDF) dice
Del mismo modo, la sección 6.5.14 El operador lógico OR dice
Se puede encontrar una redacción similar en los estándares de C ++, consulte la sección 5.14 en este borrador de copia . Como los correctores observan en otra respuesta, si anula && o ||, ambos operandos deben evaluarse a medida que se convierte en una llamada de función regular.
fuente
Sí, lo exige (tanto el orden de evaluación como el cortocircuito). En su ejemplo, si todas las funciones devuelven verdadero, el orden de las llamadas es estrictamente de la función A, luego la función B y luego la función C. Utilizado para esto como
Lo mismo para el operador de coma:
Se dice entre la izquierda y operando de la derecha de
&&
,||
,,
y entre la primera y la segunda / tercera operando de?:
(operador condicional) es un "punto de secuencia". Cualquier efecto secundario se evalúa completamente antes de ese punto. Entonces, esto es seguro:Tenga en cuenta que el operador de coma no debe confundirse con la coma sintáctica utilizada para separar las cosas:
El estándar C ++ dice en
5.14/1
:Y en
5.15/1
:Dice para ambos al lado de aquellos:
Además de eso,
1.9/18
dicefuente
Directamente del viejo K&R:
fuente
Ten mucho, mucho cuidado.
Para los tipos fundamentales, estos son operadores de acceso directo.
Pero si define estos operadores para su propia clase o tipos de enumeración, no son atajos. Debido a esta diferencia semántica en su uso en estas circunstancias diferentes, se recomienda no definir estos operadores.
Para los tipos fundamentales
operator &&
yoperator ||
para los, el orden de evaluación es de izquierda a derecha (de lo contrario, el atajo sería difícil :-) Pero para los operadores sobrecargados que defina, estos son básicamente azúcar sintáctico para definir un método y, por lo tanto, el orden de evaluación de los parámetros es indefinidofuente
Su pregunta se reduce a la precedencia del operador C ++ y la asociatividad. Básicamente, en expresiones con múltiples operadores y sin paréntesis, el compilador construye el árbol de expresión siguiendo estas reglas.
Por precedencia, cuando tiene algo así
A op1 B op2 C
, puede agrupar las cosas como(A op1 B) op2 C
oA op1 (B op2 C)
. Siop1
tiene mayor prioridad queop2
, obtendrá la primera expresión. De lo contrario, obtendrás el segundo.Para la asociatividad, cuando tienes algo así
A op B op C
, puedes volver a agrupar los delgados como(A op B) op C
oA op (B op C)
. Siop
ha dejado asociatividad, terminamos con la primera expresión. Si tiene la asociatividad correcta, terminamos con la segunda. Esto también funciona para operadores en el mismo nivel de precedencia.En este caso particular,
&&
tiene mayor prioridad que||
, por lo que la expresión se evaluará como(a != "" && it == seqMap.end()) || isEven
.El orden en sí es "de izquierda a derecha" en la forma del árbol de expresión. Entonces primero evaluaremos
a != "" && it == seqMap.end()
. Si es cierto, toda la expresión es verdadera, de lo contrario vamos aisEven
. El procedimiento se repite recursivamente dentro de la subexpresión izquierda, por supuesto.Tidbits interesantes, pero el concepto de precedencia tiene sus raíces en la notación matemática. Lo mismo sucede en
a*b + c
, donde*
tiene mayor prioridad que+
.Aún más interesante / oscuro, para una expresión no enfatizada
A1 op1 A2 op2 ... opn-1 An
, donde todos los operadores tienen la misma precedencia, el número de árboles de expresión binaria que podríamos formar viene dado por los llamados números catalanes . Para grandesn
, estos crecen extremadamente rápido. refuente
Si confías en Wikipedia:
C (lenguaje de programación)
fuente