stringtranslate.com

Punto de secuencia

En C y C++ , un punto de secuencia define cualquier punto en la ejecución de un programa informático en el que se garantiza que se habrán realizado todos los efectos secundarios de las evaluaciones anteriores y que aún no se ha realizado ningún efecto secundario de las evaluaciones posteriores. Son un concepto fundamental para determinar la validez de las expresiones y, si son válidas, los posibles resultados de las mismas. A veces es necesario añadir más puntos de secuencia para definir una expresión y garantizar un único orden válido de evaluación.

Con C11 y C++11 , el término punto de secuencia ha sido reemplazado por el de secuenciación. Existen tres posibilidades: [1] [2] [3]

  1. La evaluación de una expresión puede secuenciarse antes que la de otra expresión o, equivalentemente, la evaluación de la otra expresión puede secuenciarse después de la de la primera.
  2. La evaluación de las expresiones está secuenciada de forma indeterminada, es decir, una se secuencia antes que la otra, pero no se especifica cuál.
  3. La evaluación de las expresiones no está secuenciada.

La ejecución de evaluaciones no secuenciadas puede superponerse, lo que puede dar lugar a un comportamiento indefinido potencialmente catastrófico si comparten el estado . Esta situación puede surgir en cálculos paralelos , lo que provoca condiciones de carrera , pero el comportamiento indefinido también puede dar lugar a situaciones de un solo subproceso. Por ejemplo, a[i] = i++;(donde aes una matriz y ies un entero) tiene un comportamiento indefinido.

Ejemplos de ambigüedad

Consideremos dos funciones f() y g(). En C y C++, el +operador no está asociado a un punto de secuencia y, por lo tanto, en la expresión f()+g() es posible que o f()se g()ejecute primero. El operador coma introduce un punto de secuencia y, por lo tanto, en el código f(),g()se define el orden de evaluación: f()se llama a primero y g()se llama a después.

Los puntos de secuencia también entran en juego cuando la misma variable se modifica más de una vez dentro de una sola expresión. Un ejemplo que se cita a menudo es la expresión de Ci=i++ , que aparentemente asigna isu valor anterior e incrementa i. El valor final de ies ambiguo, porque, dependiendo del orden de evaluación de la expresión, el incremento puede ocurrir antes, después o intercalado con la asignación. La definición de un lenguaje en particular puede especificar uno de los comportamientos posibles o simplemente decir que el comportamiento es undefined . En C y C++, la evaluación de una expresión de este tipo produce un comportamiento undefined. [4] Otros lenguajes, como C# , definen la precedencia del operador de asignación e incremento de tal manera que el resultado de la expresión i=i++está garantizado.

Comportamiento

Hasta C++03

En C [5] y C++, [6] los puntos de secuencia aparecen en los siguientes lugares. (En C++, los operadores sobrecargados actúan como funciones y, por lo tanto, los operadores que han sido sobrecargados introducen puntos de secuencia de la misma manera que las llamadas a funciones).

  1. Entre la evaluación de los operandos izquierdo y derecho de los operadores&& ( AND lógico ), ||( OR lógico ) (como parte de la evaluación de cortocircuito ) y coma . Por ejemplo, en la expresión , todos los efectos secundarios de la subexpresión se completan antes de cualquier intento de acceder a .*p++ != 0 && *q++ != 0*p++ != 0q
  2. Entre la evaluación del primer operando del operador condicional ternario y su segundo o tercer operando. Por ejemplo, en la expresión hay un punto de secuencia después del primer operando , lo que significa que ya se ha incrementado en el momento en que se ejecuta la segunda instancia.a = (*p++) ? (*p++) : 0*p++
  3. Al final de una expresión completa. Esta categoría incluye las declaraciones de expresión (como la de asignación ), las declaraciones de retorno , las expresiones de control de las declaraciones , , o - y cada una de las tres expresiones de una declaración.a=b;ifswitchwhiledowhilefor
  4. Antes de que se introduzca una función en una llamada de función. No se especifica el orden en el que se evalúan los argumentos, pero este punto de secuencia significa que todos sus efectos secundarios se completan antes de que se introduzca la función. En la expresión , se llama con un parámetro del valor original de , pero se incrementa antes de entrar en el cuerpo de . De forma similar, y se actualizan antes de entrar en y respectivamente. Sin embargo, no se especifica en qué orden se ejecutan , , ni en qué orden se incrementan , , . Si el cuerpo de accede a las variables y , puede encontrar que se han incrementado ambas, ninguna o solo una de ellas. (La llamada de función no es un uso del operador de coma; el orden de evaluación de , , y no está especificado).f(i++) + g(j++) + h(k++)fiifjkghf()g()h()ijkfjkf(a,b,c)abc
  5. En el retorno de una función, después de que el valor de retorno se copia en el contexto de llamada. (Este punto de secuencia solo se especifica en el estándar C++; está presente solo de manera implícita en C. [7] )
  6. Al final de un inicializador ; por ejemplo, después de la evaluación de 5en la declaración .int a = 5;
  7. Entre cada declarador en cada secuencia de declaradores; por ejemplo, entre las dos evaluaciones de en . [8] (Este no es un ejemplo del operador de coma).a++int x = a++, y = a++
  8. Después de cada conversión asociada a un especificador de formato de entrada/salida. Por ejemplo, en la expresión , hay un punto de secuencia después de que se evalúa y antes de imprimir .printf("foo %n %d", &a, 42)%n42

C11 y C++11

En parte debido a la introducción del soporte de lenguaje para subprocesos, C11 y C++11 introdujeron una nueva terminología para el orden de evaluación. Una operación puede ser "secuenciada antes" de otra, o las dos pueden ser secuenciadas "indeterminadamente" (una debe completarse antes que la otra) o "no secuenciadas" (las operaciones en cada expresión pueden estar intercaladas).

C++17

C++17 restringió varios aspectos del orden de evaluación. La newexpresión siempre realizará la asignación de memoria antes de evaluar los argumentos del constructor. Se garantiza que los operadores <<, >>, ., .*, ->*, y el operador de llamada de subíndice y función se evaluarán de izquierda a derecha (ya sea que estén sobrecargados o no). Por ejemplo, el código

std :: cout << a () << b () << c (); // analizado como (((std::cout << a()) << b()) << c());       

Se garantiza que se llamará a a, by cen ese orden. El lado derecho de cualquier operador de tipo asignación se evalúa antes que el lado izquierdo, por lo que b() *= a();se garantiza que se evaluará aprimero. Finalmente, aunque el orden en el que se evalúan los parámetros de la función sigue estando definido por la implementación, ya no se permite que el compilador intercale subexpresiones en varios parámetros. [9]

Véase también

Referencias

  1. ^ "ISO/IEC 14882:2011" . Consultado el 4 de julio de 2012 .
  2. ^ "Una alternativa más detallada a los puntos de secuencia (revisada) (WG21/N2239 J16/07-0099)" . Consultado el 5 de julio de 2012 .
  3. ^ "Orden de evaluación" . Consultado el 14 de octubre de 2015 .
  4. ^ Cláusula 6.5#2 de la especificación C99 : "Entre el punto de secuencia anterior y el siguiente, el valor almacenado de un objeto debe modificarse como máximo una vez mediante la evaluación de una expresión. Además, se debe acceder al valor anterior únicamente para determinar el valor que se almacenará".
  5. ^ El Anexo C de la especificación C99 enumera las circunstancias bajo las cuales se puede suponer un punto de secuencia.
  6. ^ El estándar C++ de 1998 enumera los puntos de secuencia para ese lenguaje en la sección 1.9, párrafos 16 a 18.
  7. ^ Estándar C++, ISO 14882:2003, sección 1.9, nota al pie 11.
  8. ^ Estándar C++, ISO 14882:2003, sección 8.3: "Cada declarador init en una declaración se analiza por separado como si estuviera en una declaración por sí mismo".
  9. ^ Dos Reis, Gabriel; Sutter, Herb; Caves, Jonathan (23 de junio de 2016). "Refinamiento del orden de evaluación de expresiones para C++ idiomático" (PDF) . open-std.org . págs. 1–5 . Consultado el 28 de abril de 2023 .

Enlaces externos