No está definido porque se modifica x
dos veces entre puntos de secuencia. El estándar dice que no está definido, por lo tanto, no está definido.
Eso lo sé.
¿Pero por qué?
Tengo entendido que prohibir esto permite a los compiladores optimizar mejor. Esto podría haber tenido sentido cuando se inventó C, pero ahora parece un argumento débil.
Si reinventamos C hoy, ¿lo haríamos de esta manera, o podríamos hacerlo mejor?
¿O tal vez hay un problema más profundo que hace que sea difícil definir reglas consistentes para tales expresiones, por lo que es mejor prohibirlas?
Supongamos que reinventamos C hoy. Me gustaría sugerir reglas simples para expresiones como x=x++
, que me parecen funcionar mejor que las reglas existentes.
Me gustaría conocer su opinión sobre las reglas sugeridas en comparación con las existentes u otras sugerencias.
Reglas sugeridas:
- Entre los puntos de secuencia, el orden de evaluación no está especificado.
- Los efectos secundarios tienen lugar de inmediato.
No hay un comportamiento indefinido involucrado. Las expresiones evalúan este valor o ese, pero seguramente no formatearán su disco duro (curiosamente, nunca he visto una implementación donde x=x++
formatee el disco duro).
Expresiones de ejemplo
x=x++
- Bien definido, no cambiax
.
Primero,x
se incrementa (inmediatamente cuandox++
se evalúa), luego se almacena su valor anteriorx
.x++ + ++x
- Incrementax
dos veces, evalúa a2*x+2
.
Aunque cualquier lado puede evaluarse primero, el resultado esx + (x+2)
(lado izquierdo primero) o(x+1) + (x+1)
(lado derecho primero).x = x + (x=3)
- Sin especificar,x
establecido enx+3
o6
.
Si el lado derecho se evalúa primero, esx+3
. También es posible quex=3
se evalúe primero, así es3+3
. En cualquier caso, lax=3
asignación ocurre inmediatamente cuandox=3
se evalúa, por lo que el valor almacenado se sobrescribe con la otra asignación.x+=(x=3)
- Bien definido, se establecex
en 6.
Se podría argumentar que esto es solo una forma abreviada de la expresión anterior.
Pero diría que+=
debe ejecutarse despuésx=3
, y no en dos partes (leerx
, evaluarx=3
, agregar y almacenar nuevo valor).
¿Cuál es la ventaja?
Algunos comentarios plantearon este buen punto.
Ciertamente no creo que expresiones como x=x++
deberían usarse en ningún código normal.
En realidad, soy mucho más estricto que eso: creo que el único buen uso x++
es x++;
solo.
Sin embargo, creo que las reglas del lenguaje deben ser lo más simples posible. De lo contrario, los programadores simplemente no los entienden. La regla que prohíbe cambiar una variable dos veces entre puntos de secuencia es ciertamente una regla que la mayoría de los programadores no entienden.
Una regla muy básica es esta:
si A es válido y B es válido, y se combinan de manera válida, el resultado es válido.
x
es un valor L válido, x++
es una expresión válida y =
es una forma válida de combinar un valor L y una expresión, entonces, ¿por qué x=x++
no es legal?
El estándar C hace una excepción aquí, y esta excepción complica las reglas. Puede buscar en stackoverflow.com y ver cuánto confunde esta excepción con las personas.
Así que digo: deshazte de esta confusión.
=== Resumen de respuestas ===
¿Por qué hacer eso?
Traté de explicarlo en la sección anterior: quiero que las reglas de C sean simples.Potencial de optimización:
esto toma algo de libertad del compilador, pero no vi nada que me convenciera de que podría ser significativo.
La mayoría de las optimizaciones aún se pueden hacer. Por ejemplo,a=3;b=5;
puede reordenarse, aunque el estándar especifique el orden. Expresiones comoa=b[i++]
todavía se pueden optimizar de manera similar.No puede cambiar el estándar existente.
Lo admito, no puedo. Nunca pensé que podría seguir adelante y cambiar los estándares y los compiladores. Solo quería pensar si las cosas podrían haberse hecho de manera diferente.
x
a sí mismo, y si desea aumentarx
, puede decirx++;
: no es necesario realizar la tarea. Yo diría que no debería definirse solo porque sería difícil recordar lo que se supone que sucederá.