varias superponer studio lineas histogramas graficos graficas c sequence-points

studio - superponer graficas en r



puntos de secuencia en c (4)

Ampliando la respuesta de paxdiablo con un ejemplo.

Asume la declaración

x = i++ * ++j;

Hay tres efectos secundarios: asignar el resultado de i * (j+1) a x, agregar 1 a i y agregar 1 a j. El orden en que se aplican los efectos secundarios no está especificado; i y j pueden incrementarse cada vez que se evalúan, o pueden no incrementarse hasta que ambos hayan sido evaluados, pero antes de que se haya asignado x, o pueden no incrementarse hasta que se haya asignado x.

El punto de secuencia es el punto donde se han aplicado todos los efectos secundarios (x, iy j han sido actualizados), independientemente del orden en el que se aplicaron.

Un punto de secuencia en la programación imperativa define cualquier punto en la ejecución de un programa de computadora en el que se garantiza que se hayan realizado todos los efectos secundarios de las evaluaciones previas, y no se han realizado aún los efectos secundarios de las evaluaciones posteriores.

¿Qué significa esto? ¿Alguien puede explicarlo en palabras simples?


Cuando ocurre un punto de secuencia, básicamente significa que tiene garantizado que todas las operaciones previas están completas.

Cambiar una variable dos veces sin un punto de secuencia intermedio es un ejemplo de comportamiento indefinido.

Por ejemplo, i = i++; no está definido porque no hay punto de secuencia entre los dos cambios en i .

Wikipedia tiene una lista de los puntos de secuencia en los estándares C y C ++ aunque la lista definitiva siempre debe tomarse del estándar ISO. Del anexo C99 C:

Los siguientes son los puntos de secuencia descritos en 5.1.2.3:

  • La llamada a una función, después de que los argumentos hayan sido evaluados (6.5.2.2).
  • El final del primer operando de los siguientes operadores: AND lógico && (6.5.13); O lógico || (6.5.14); condicional? (6.5.15); coma, (6.5.17).
  • El final de un declarador completo: declaradores (6.7.5);
  • El final de una expresión completa: un inicializador (6.7.8); la expresión en una declaración de expresión (6.8.3); la expresión de control de una declaración de selección (si o cambio) (6.8.4); la expresión de control de una sentencia while o do (6.8.5); cada una de las expresiones de una declaración for (6.8.5.3); la expresión en una declaración de retorno (6.8.6.4).
  • Inmediatamente antes de que una función de biblioteca regrese (7.1.4).
  • Después de las acciones asociadas con cada especificador de conversión de función de entrada / salida formateado (7.19.6, 7.24.2).
  • Inmediatamente antes e inmediatamente después de cada llamada a una función de comparación, y también entre cualquier llamada a una función de comparación y cualquier movimiento de los objetos pasados ​​como argumentos para esa llamada (7.20.5).

C11 ha cambiado la redacción. Parece que se rompió el operador ternario y agregó algunos detalles más:

Los siguientes son los puntos de secuencia descritos en 5.1.2.3:

  • Entre las evaluaciones del designador de función y los argumentos reales en una llamada de función y la llamada real. (6.5.2.2).
  • Entre las evaluaciones del primer y segundo operandos de los siguientes operadores: AND lógico && (6.5.13); O lógico || (6.5.14); coma, (6.5.17).
  • Entre las evaluaciones del primer operando del operador condicional?: Y cualquiera del segundo y tercer operandos se evalúa (6.5.15).
  • El final de un declarador completo: declaradores (6.7.6);
  • Entre la evaluación de una expresión completa y la siguiente expresión completa a evaluar. Las siguientes son expresiones completas: un inicializador (6.7.9); la expresión en una declaración de expresión (6.8.3); la expresión de control de una declaración de selección (si o cambio) (6.8.4); la expresión de control de una sentencia while o do (6.8.5); cada una de las expresiones de una declaración for (6.8.5.3); la expresión en una declaración de retorno (6.8.6.4).
  • Inmediatamente antes de que una función de biblioteca regrese (7.1.4).
  • Después de las acciones asociadas con cada especificador de conversión de función de entrada / salida formateado (7.21.6, 7.28.2).
  • Inmediatamente antes e inmediatamente después de cada llamada a una función de comparación, y también entre cualquier llamada a una función de comparación y cualquier movimiento de los objetos pasados ​​como argumentos para esa llamada (7.22.5).

Significa que un compilador puede hacer optimizaciones funky, trucos y magia, pero debe alcanzar un estado bien definido en los llamados puntos de secuencia.


Una cosa importante a tener en cuenta acerca de los puntos de secuencia es que no son globales, sino que deben considerarse como un conjunto de restricciones locales. Por ejemplo, en la declaración

a = f1(x++) + f2(y++);

Hay un punto de secuencia entre la evaluación de x ++ y la llamada a f1, y otro punto de secuencia entre la evaluación de y ++ y la llamada a f2. Sin embargo, no hay garantía de si x se incrementará antes o después de llamar a f2, ni si y se incrementará antes o después de que se llame a x. Si f1 cambia y o f2 cambia x, los resultados serán indefinidos (sería legítimo que el código generado del compilador lea, por ejemplo, x e y, incremente x, llame a f1, verifique y contra el valor leído previamente, y - si cambió - ir en un alboroto buscando y destruyendo todos los videos y mercancías de Barney; no creo que ningún compilador real genere código que realmente lo haga, por desgracia, pero estaría permitido según el estándar).