Namespaces
Variants

Order of evaluation

From cppreference.net

El orden de evaluación de los operandos de cualquier operador de C++, incluyendo el orden de evaluación de los argumentos de función en una expresión de llamada a función, y el orden de evaluación de las subexpresiones dentro de cualquier expresión no está especificado (excepto donde se indica a continuación). El compilador los evaluará en cualquier orden, y puede elegir otro orden cuando la misma expresión sea evaluada nuevamente.

No existe el concepto de evaluación de izquierda a derecha o de derecha a izquierda en C, lo cual no debe confundirse con la asociatividad de izquierda a derecha y de derecha a izquierda de los operadores: la expresión f1 ( ) + f2 ( ) + f3 ( ) se analiza como ( f1 ( ) + f2 ( ) ) + f3 ( ) debido a la asociatividad de izquierda a derecha del operator + , pero la llamada a la función f3 ( ) podría evaluarse primero, al último, o entre f1 ( ) o f2 ( ) en tiempo de ejecución.

Contenidos

Definiciones

Evaluaciones

Hay dos tipos de evaluaciones realizadas por el compilador para cada expresión o subexpresión (ambas son opcionales):

  • cálculo de valor  : cálculo del valor que es devuelto por la expresión. Esto puede implicar la determinación de la identidad del objeto ( evaluación lvalue ) o la lectura del valor previamente asignado a un objeto (evaluación rvalue).
  • efecto secundario  : acceso (lectura o escritura) a un objeto designado por un volatile lvalue, modificación (escritura) de un objeto , sincronización atómica (desde C11) , modificación de un archivo, modificación del entorno de punto flotante (si está soportado), o llamar a una función que realice cualquiera de estas operaciones.

Si una expresión no produce efectos secundarios y el compilador puede determinar que el valor no se utiliza, la expresión puede no ser evaluada .

Ordenamiento

Secuenciado-antes es una relación asimétrica, transitiva y por pares entre evaluaciones dentro del mismo hilo (puede extenderse a través de hilos si están involucrados tipos atómicos y barreras de memoria).

  • Si un punto de secuencia está presente entre las subexpresiones E1 y E2 , entonces tanto el cálculo de valor como los efectos secundarios de E1 están secuenciados-antes de todo cálculo de valor y efecto secundario de E2 .
  • Si la evaluación A está secuenciada antes que la evaluación B, entonces la evaluación de A se completará antes de que comience la evaluación de B.
  • Si A no está secuenciada antes que B y B está secuenciada antes que A, entonces la evaluación de B se completará antes de que comience la evaluación de A.
  • Si A no está secuenciada antes que B y B no está secuenciada antes que A, entonces existen dos posibilidades:
    • las evaluaciones de A y B no están secuenciadas: pueden realizarse en cualquier orden y pueden superponerse (dentro de un único hilo de ejecución, el compilador puede entrelazar las instrucciones de CPU que componen A y B)
    • las evaluaciones de A y B están indeterminadamente secuenciadas: pueden realizarse en cualquier orden pero no pueden superponerse: o A se completará antes que B, o B se completará antes que A. El orden puede ser opuesto la próxima vez que se evalúe la misma expresión.
(desde C11)

Reglas

1) Existe un punto de secuencia después de la evaluación de todos los argumentos de la función y del designador de función, y antes de la llamada real a la función.
2) Existe un punto de secuencia después de la evaluación del primer operando (izquierdo) y antes de la evaluación del segundo operando (derecho) de los siguientes operadores binarios: && (AND lógico), || (OR lógico), y , (coma).
3) Existe un punto de secuencia después de la evaluación del primer operando (izquierdo) y antes de la evaluación del segundo o tercer operando (cualquiera que sea evaluado) del operador condicional ?:
4) Existe un punto de secuencia después de la evaluación de una expresión completa (una expresión que no es una subexpresión: típicamente algo que termina con un punto y coma o una sentencia de control de if / switch / while / do ) y antes de la siguiente expresión completa.
5) Hay un punto de secuencia al final de un declarador completo.
6) Hay un punto de secuencia inmediatamente antes del retorno de una función de biblioteca.
7) Hay un punto de secuencia después de la acción asociada con cada especificador de conversión en E/S formateada (en particular, está bien formado que scanf escriba diferentes campos en la misma variable y que printf lea y modifique o modifique la misma variable más de una vez usando % n )
8) Hay puntos de secuencia antes e inmediatamente después de cada llamada a una función de comparación realizada por las funciones de biblioteca qsort y bsearch , así como entre cualquier llamada a la función de comparación y el movimiento de los objetos asociados realizado por qsort
(desde C99)
9) Los cálculos de valor (pero no los efectos secundarios) de los operandos de cualquier operador están secuenciados antes del cálculo de valor del resultado del operador (pero no sus efectos secundarios).
10) El efecto secundario (modificación del argumento izquierdo) del operador de asignación directa y de todos los operadores de asignación compuesta está secuenciado después del cálculo de valor (pero no los efectos secundarios) de ambos argumentos, izquierdo y derecho.
11) El cálculo de valor de los operadores de post-incremento y post-decremento está secuenciado antes de su efecto secundario.
12) Una llamada a función que no está secuenciada antes o secuenciada después de otra llamada a función está indeterminadamente secuenciada (las instrucciones de CPU que constituyen diferentes llamadas a función no pueden entrelazarse, incluso si las funciones están en línea)
13) En expresiones de lista de inicialización , todas las evaluaciones están indeterminadamente secuenciadas
14) Con respecto a una llamada a función indeterminadamente secuenciada, la operación de los operadores de asignación compuesta, y tanto las formas de prefijo como de postfijo de los operadores de incremento y decremento son evaluaciones únicas.
(desde C11)

Comportamiento indefinido

1) Si un efecto secundario sobre un objeto escalar no está secuenciado respecto a otro efecto secundario sobre el mismo objeto escalar, el comportamiento es indefinido .
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) Si un efecto secundario sobre un objeto escalar no está secuenciado en relación con un cálculo de valor que utiliza el valor del mismo objeto escalar, el comportamiento es indefinido.
f(i, i++); // undefined behavior
a[i] = i++; // undefined behavior
3) Las reglas anteriores se aplican siempre que al menos un orden permitido de las subexpresiones permita dicho efecto secundario no secuenciado.

Véase también

Precedencia de operadores que define cómo se construyen las expresiones a partir de su representación en código fuente.

Documentación de C++ para Orden de evaluación