Pregunta

Hace unos días hubo una discusión aquí acerca de si la expresión

  

i = ++ i + 1

invoca UB (Comportamiento no definido) o no.

Finalmente, la conclusión fue hecho que invoca UB como el valor de 'i' está cambiando más de una vez entre dos puntos de secuencia.

I estaba involucrado en una discusión con Johannes Schaub en ese mismo hilo. Según él

  

i = (i, i ++, i) 1 ------ (1) / * invoca UB así * /

he dicho (1) no invoca UB porque los efectos secundarios de las subexpresiones anteriores se borran por el operador de coma '' entre i y i ++ y entre i ++ y i.

Luego se dio la siguiente explicación:

  

"Si el punto de secuencia después de i ++ completa de todos los efectos secundarios antes de ella, pero no hay nada que detenga el efecto secundario asignación de superposición con el efecto secundario de i ++. El problema de fondo es que el efecto secundario de una asignación es no especificado a suceder después o antes de la evaluación de los dos operandos de la asignación, y por lo tanto puntos de secuencia no puede hacer nada con respecto a la protección de este: secuencia señala inducir un orden parcial: el hecho de que hay un punto de secuencia después y antes de i ++ no significa que todos los efectos secundarios son secuenciados con respecto a i .

     

Además, el aviso de que simplemente un punto de secuencia significa nada: El orden de las evaluaciones no está dictada por la forma de código. Ha dictado por reglas semánticas. En este caso, no hay una regla semántica decir, cuando el efecto secundario de asignación ocurre con respecto a la evaluación de sus dos operandos o subexpresiones de los operandos".

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

"en ciertos puntos determinados en la secuencia de ejecución llamados puntos de secuencia, todos los efectos secundarios de las evaluaciones anteriores, debe ser completa y se han llevado a cabo ningún efecto secundario de las evaluaciones posteriores."

Desde entonces, los operadores de coma también especifican el orden de ejecución el efecto secundario de i ++ han sido cancelados cuando se llega a la última i.He (Johannes) habría tenido razón tenía el orden de evaluación no se ha especificado (pero en el caso de operador coma es bien especificado).

Así que sólo quiero saber si (1) invoca UB o no ?. ¿Puede alguien dar otra explicación válida?

Gracias!

¿Fue útil?

Solución

dice que el estándar de C esto unos operadores de asignación (C90 6.3.16 o C99 operadores 6.5.16 asignación):

  

El efecto secundario de la actualización del valor almacenado del operando de la izquierda se producirá entre el anterior y el siguiente punto de la secuencia.

Me parece que en la declaración:

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

el punto de secuencia 'anterior' para el operador de asignación sería el segundo operador de coma y el 'siguiente' punto secuencia serían el final de la expresión. Así que yo 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 debido a que el orden de evaluación de los 2 operandos del operador de asignación no está definida, y en este caso en lugar del problema es cuando los efectos secundarios del operador de asignación se lleva a cabo, el problema es que no sabe si el valor de i utilizado en el operando de la manija izquierda será evaluado antes o después de la mano derecha. Este orden de Evaluación problema no se produce en el primer ejemplo ya que en esa expresión el valor de i no se utiliza realmente en el lado izquierdo - todo lo que el operador de asignación le interesa es el "valor-i-dad" de i .

Pero también creo que todo esto es bastante vagos (y mi comprensión de los matices involucrados son lo suficientemente vagos) que no me sorprendería si alguien me puede convencer de lo contrario (en cualquiera de recuento).

Otros consejos

Creo que la siguiente expresión sin duda ha indefinido comportamiento.

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

La razón es que el operador coma especifica puntos de secuencia entre las subexpresiones entre paréntesis, pero no especifica dónde se produce en esa secuencia de la evaluación del operando izquierdo de +. Una posibilidad es entre el i++ puntos de secuencia que rodea y esto viola el 5/4 como i se escribe entre dos puntos de secuencia sino que también se lee dos veces entre los mismos puntos de secuencia y no sólo para determinar el valor para ser almacenados, sino también para determinar la valor del primer operando al operador +.

Este comportamiento también se ha indefinido.

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

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

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

A pesar de que se aplican los mismos principios, i debe ser "evaluados" como un valor-modificable y puede hacerse en cualquier momento, pero no estoy convencido de que su valor está siempre leer como parte de este. (¿O hay otra restricción que la expresión viola a causar UB?)

El (i, i++, i) sub-expresión ocurre como parte de la determinación del valor a ser almacenada y que sub-expresión contiene un punto de secuencia después de que el almacenamiento de un valor a i. No veo ninguna manera de que esto no requiere el efecto secundario de i++ ser completa antes de la determinación del valor a ser almacenada y, por tanto, el punto más temprana posible que el efecto secundario de asignación podría ocurrir.

Después de este punto el valor de i sequnce se lee como máximo una vez y sólo para determinar el valor que se almacena de nuevo a i, por lo que esta última parte está muy bien.

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

no invoca un comportamiento indefinido. El efecto secundario de i++ se llevará a cabo antes de la evaluación del siguiente punto de secuencia, que se denota por la coma siguiente, y también antes de la asignación.

sudoku Niza idioma, sin embargo. : -)

editar:. Hay una explicación más elaborada aquí

Yo estaba confundido al principio respecto a la declaración de Johannes (litb) pero se mencionó que en:

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


  Si es la asignación, y es un incremento. :s: es un punto de secuencia, a continuación, los efectos secundarios pueden ser secuenciados como sigue entre los puntos de secuencia: (i :s: i++< a ><n> :s: i) + 1. El valor de la i escalar se cambió dos veces entre el primer y segundo punto de secuencia aquí. El orden en que ocurre la asignación y el incremento es no especificada, y ya que entre ellos no hay punto de la secuencia, no es ni siquiera atómica con respecto a cada uno otro.Esto es uno de pedido permitido permitidos por el ordenamiento no especificado de estos efectos secundarios.

     

Esto es diferente a (i++, i++), ya que el orden de evaluación de las dos subexpresiones es de izquierda a derecha, y en el punto de secuencia entre ellos, el incremento de la evaluación anterior deberá ser completa, y el siguiente incremento no se han tomado todavía sitio. Esto hace cumplir que no hay ningún cambio del valor de i entre dos puntos de secuencia, lo que hace (i++, i++) válido
  

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

  

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

es decir. el valor del operando derecho necesita ser conocido antes el efecto secundario de asignación (modificación del valor almacenado en el objeto correspondiente al operando de la izquierda)

  

6.5.17 (2) El operando de la izquierda de un operador de coma se evalúa como una expresión vacío; hay un punto de secuencia después de su evaluación. A continuación, se evalúa el operando de la derecha; el resultado tiene su tipo y valor.

es decir. el operando de la derecha de la operación de coma debe ser evaluado para conocer el valor y el tipo de la expresión coma (y el valor del operando de la derecha para mi ejemplo).

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

Por favor, corríjanme si estoy equivocado.


scroll top