¿Puede alguien explicar si i = x[i]++; conducir a un comportamiento indefinido?
Hay C11, 6.5 Expresiones, 2 (énfasis añadido):
Si un efecto secundario en un objeto escalar no está secuenciado en relación con un efecto secundario diferente en el mismo objeto escalar o un cálculo de valor utilizando el valor del mismo objeto escalar , el comportamiento no está definido. Si hay varios ordenamientos permitidos de las subexpresiones de una expresión, el comportamiento no está definido si se produce un efecto secundario sin secuencia en cualquiera de los ordenamientos. 84)
Según entiendo:
¿Hay "múltiples pedidos permitidos"?
En general: ¿cómo puede i = x[i]++; interpretarse con puntos de secuencia, efectos secundarios y comportamiento indefinido (si corresponde)?
UPD. Conclusión: la i = x[i]++; conduce a 2 efectos secundarios:
La Norma no define el orden en que se producen los efectos secundarios.
Por lo tanto, según C11, 4. Conformidad, 2:
El comportamiento indefinido se indica de otro modo en esta Norma Internacional mediante las palabras "comportamiento indefinido" o mediante la omisión de cualquier definición explícita de comportamiento .
Los experimentos muestran que GCC/LLVM/ICC tienen orden 1-2 , mientras que MSVC (y algunos otros) tienen orden 2-1 .
Extra (especulando): ¿por qué no convertirlo en un comportamiento no especificado? Ejemplo: "un ejemplo de comportamiento no especificado es el orden en que se producen los efectos secundarios "?
Imagina:
i = 3; x[] = {1, 1, 1, 1, 1}; Entonces, x[i] es igual a 1, x[i]++ es igual a 2 y x se convierte en {1, 1, 2, 1, 1} , y i se convierte en 1.
¿Por qué habría algún comportamiento indefinido?
si fuera cierto que
- no hay "efecto secundario diferente en el mismo objeto escalar"
- no hay "cálculo de valor usando el valor del mismo objeto escalar"
(en cada orden permitido de las subexpresiones), entonces la disposición que cita no presentaría ningún problema en particular. Es decir, el antecedente de su "si" no se mantendría, por lo que la consecuencia de ese "si" (comportamiento indefinido) no se afirmaría.
Sin embargo, hay un efecto secundario en i y un cálculo de valor usando el valor de i . El primero es el efecto secundario de la asignación y el segundo es el cálculo del valor de x[i]++ . Esto no es un problema, sin embargo, porque, para todas las formas de asignación,
El efecto secundario de actualizar el valor almacenado del operando izquierdo se secuencia después de los cálculos de valor de los operandos izquierdo y derecho.
(C17 6.5.16/3)
Además, para completar,
Los cálculos de valor de los operandos de un operador se secuencian antes del cálculo de valor del resultado del operador.
(C17 6.5/1)
Por lo tanto, el efecto secundario de la asignación en i se secuencia después del cálculo del valor de x[i]++ , que se secuencia después de la evaluación de i .
Hay un cálculo de valor utilizando el valor del mismo objeto escalar. x[i] usa el valor de i .
Desde C11, hay una relación de secuencia en la asignación.
El efecto secundario de actualizar el valor almacenado del operando izquierdo se secuencia después de los cálculos de valor de los operandos izquierdo y derecho.
(C11 6.5.16/3)
Antes de eso, la forma en que el estándar discutía las expresiones era más flexible. No describía una relación secuencial anterior . En su lugar tenemos:
Entre el punto de secuencia anterior y el siguiente, el valor almacenado de un objeto se modificará como máximo una vez mediante la evaluación de una expresión. Además, el valor anterior se leerá solo para determinar el valor que se almacenará.
No está leyendo el valor "aparte de determinar el valor que se almacenará", por lo que se define el comportamiento.
(C99 6.5/2)