una total resueltos relación relacion qué parcial orden minimales maximales matematicas estricto ejercicios ejemplos discretas cadena antisimetrica c++ c expression language-lawyer

c++ - total - relacion de orden parcial matematicas discretas



Puntos de secuencia y orden parcial (4)

Hace unos días hubo una discusión here sobre si la expresión

i = ++ i + 1

invoca UB (Comportamiento Indefinido) o no.

Finalmente, se llegó a la conclusión de que invoca a UB ya que el valor de ''i'' está cambiando más de una vez entre dos puntos de secuencia.

Estuve involucrado en una discusión con Johannes Schaub en ese mismo hilo. De acuerdo con él

i = (i, i ++, i) +1 ------ (1) / * invoca UB también * /

Dije que (1) no invoca a UB porque los efectos secundarios de las subexpresiones previas son borrados por el operador de coma '','' entre i e i ++ y entre i ++ e i.

Luego dio la siguiente explicación:

"Sí, el punto de secuencia después de i ++ completa todos los efectos secundarios anteriores, pero no hay nada que detenga la superposición del efecto secundario de asignación con el efecto secundario de i ++. El problema subyacente es que el efecto secundario de una asignación no se especifica después o antes de la evaluación de ambos operandos de la asignación, los puntos de secuencia no pueden hacer nada para proteger esto: los puntos de secuencia inducen un orden parcial: el hecho de que exista un punto de secuencia después y antes de i ++ no significa que todos los efectos secundarios estén secuenciados con respecto a i .

Además, observe que simplemente un punto de secuencia no significa nada: el orden de las evaluaciones no está dictado por la forma del código. Está dictado por reglas semánticas. En este caso, no existe una regla semántica que indique cuándo se produce el efecto secundario de asignación con respecto a la evaluación de sus dos operandos o subexpresiones de esos operandos ".

La declaración escrita en "negrita" me confundió. Por lo que sé:

"En ciertos puntos especificados en la secuencia de ejecución llamados puntos de secuencia, todos los efectos secundarios de las evaluaciones previas deberán estar completos y no se habrán producido los efectos secundarios de las evaluaciones posteriores".

Dado que los operadores de coma también especifican el orden de ejecución, el efecto secundario de i ++ se ha cancelado cuando llegamos al último i.He (Johannes) hubiera sido correcto si no se hubiera especificado el orden de evaluación (pero en el caso del operador de coma está bien especificado )

Entonces solo quiero saber si (1) invoca UB o no ?. ¿Alguien puede dar otra explicación válida?

¡Gracias!


Al principio me confundí la declaración de Johannes (litb) pero él mencionó eso en:

i = (i, ++i, i) +1

<Johannes>
Si <a> es una asignación, y es un incremento. :s: es un punto de secuencia, luego los efectos secundarios se pueden secuenciar de la siguiente manera entre los puntos de secuencia: (i :s: i++< a ><n> :s: i) + 1 . El valor del escalar i se cambió dos veces entre el primer y el segundo punto de secuencia aquí. El orden en que ocurre la asignación y el incremento no está especificado, y dado que entre ellos no hay un punto de secuencia, ni siquiera es atómico entre sí. Este es un ordenamiento permitido permitido por el ordenamiento no especificado de estos efectos secundarios.

Esto es diferente de (i++, i++) , porque el orden de evaluación de las dos subexpresiones es de izquierda a derecha, y en el punto de secuencia entre ellas, el incremento de la evaluación previa debe estar completo, y el siguiente incremento no debe tener todavía lugar tomado. Esto impone que no hay cambio del valor de i entre dos puntos de secuencia, lo que hace que (i++, i++) válido
</ Johannes>

Esto me hizo pensar que la secuencia mencionada por litb no es válida porque según C99:

6.5.16.1 (2) En la asignación simple (=), el valor del operando derecho se convierte al tipo de la expresión de asignación y reemplaza el valor almacenado en el objeto designado por el operando izquierdo.

es decir, el valor del operando derecho debe conocerse antes del efecto secundario de asignación (modificación del valor almacenado en el objeto correspondiente al operando izquierdo)

6.5.17 (2) El operando izquierdo de un operador de coma se evalúa como una expresión vacía; hay un punto de secuencia después de su evaluación. Entonces se evalúa el operando correcto; el resultado tiene su tipo y valor.

es decir, el operando más a la derecha de la operación de coma necesita ser evaluado para conocer el valor y el tipo de la expresión de coma (y el valor del operando correcto para mi ejemplo).

Entonces, en este caso, el ''punto de secuencia anterior'' para el efecto secundario de asignación sería, en efecto, la operación de coma más a la derecha. La posible secuencia mencionada por Johannes no es válida.

Por favor, corríjame si estoy equivocado.


Creo que la siguiente expresión definitivamente tiene un comportamiento indefinido.

i + ((i, i++, i) + 1)

La razón es que el operador de coma especifica los puntos de secuencia entre subexpresiones entre paréntesis, pero no especifica dónde se produce en esa secuencia la evaluación del operando de la mano izquierda de + . Una posibilidad es entre los puntos de secuencia que rodean a i++ y esto viola el 5/4 cuando se escribe entre dos puntos de secuencia, pero también se lee dos veces entre los mismos puntos de secuencia y no solo para determinar el valor a almacenar sino también para determinar el valor del primer operando al operador + .

Esto también tiene un comportamiento indefinido.

i += (i, i++, i) + 1;

Ahora, no estoy tan seguro acerca de esta afirmación.

i = (i, i++, i) + 1;

Aunque se aplican los mismos principios, debo ser "evaluado" como un valor l modificable y puedo hacerlo en cualquier momento, pero no estoy convencido de que se lea su valor como parte de esto. (¿O hay otra restricción que la expresión viole para causar UB?)

La sub-expresión (i, i++, i) ocurre como parte de la determinación del valor que se almacenará y esa sub-expresión contiene un punto de secuencia después del almacenamiento de un valor en i . No veo ninguna manera de que esto no requiera que el efecto secundario de i++ se complete antes de la determinación del valor que se almacenará y, por lo tanto, el punto más temprano posible de que pueda ocurrir el efecto secundario de la asignación.

Después de este punto de separación, el valor de i se lee como máximo una vez y solo para determinar el valor que se almacenará en i , por lo que esta última parte está bien.


El estándar C dice esto sobre los operadores de asignación (C90 6.3.16 o C99 6.5.16 Asignación de operadores):

El efecto secundario de actualizar el valor almacenado del operando izquierdo se producirá entre el punto de secuencia anterior y el siguiente.

Me parece que en la declaración:

i=(i,i++,i)+1;

el punto de secuencia ''anterior'' al operador de asignación sería el segundo operador de coma y el ''siguiente'' punto de secuencia sería el final de la expresión. Entonces diría que la expresión no invoca un comportamiento indefinido.

Sin embargo, esta expresión:

*(some_ptr + i) = (i,i++,i)+1;

tendría un comportamiento indefinido porque el orden de evaluación de los 2 operandos del operador de asignación no está definido, y en este caso, en lugar de ser el problema cuando se produce el efecto secundario del operador de asignación, el problema es que usted no sabe si el valor de Yo utilicé el operando del mango izquierdo será evaluado antes o después del lado derecho. Este orden de problema de evaluación no ocurre en el primer ejemplo porque en esa expresión el valor de i no se usa realmente en el lado izquierdo; todo lo que le interesa al operador de asignación es la "lvalue-ness" de i .

Pero también creo que todo esto es lo suficientemente superficial (y mi comprensión de los matices involucrados son lo suficientemente esquemáticos) que no me sorprendería si alguien puede convencerme de lo contrario (en cualquier caso).


i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

No invoca un comportamiento indefinido. El efecto secundario de i++ tendrá lugar antes de la evaluación del siguiente punto de secuencia, que se denota mediante la coma que lo sigue, y también antes de la asignación.

Un buen sudoku del lenguaje, sin embargo. :-)

editar: hay una explicación más elaborada here .