es i=f(); definido cuando f modifica i?
c99 sequence-points (2)
La transferencia de control de f back a la expresión de llamada no se enumera como un punto de secuencia.
Sí lo es.
Al final de la evaluación de una expresión completa.
La expresión completa que forma una declaración de expresión, o una de las expresiones de control de if, switch, while, for, do / while, o la expresión en un inicializador o una declaración de retorno .
Tienes una declaración de retorno, por lo tanto, tienes un punto de secuencia.
Ni siquiera parece que
int f(void) { return i++; } // sequence point here, so I guess we''re good
i = f();
es indefinido. (Lo que para mí es algo raro.)
Pregunta relacionada: ¿ Alguna buena razón por la que el operador de asignación no es un punto de secuencia?
De las preguntas frecuentes de comp.lang.c inferiría que el programa a continuación no está definido. Curiosamente, solo menciona la llamada a f
como un punto de secuencia, entre el cálculo de los argumentos y la transferencia de control a f
. La transferencia de control de f
back a la expresión de llamada no se enumera como un punto de secuencia.
int f(void) { i++; return 42; }
i = f();
¿Es realmente indefinido?
Como nota final que agrego a muchas de mis preguntas, me interesa esto en el contexto del análisis estático. No estoy escribiendo esto por mí mismo, solo quiero saber si debo advertirlo en programas escritos por otros.
Eso no está indefinido en absoluto. Uno de los puntos de secuencia enumerados en el Apéndice C de C99 es el final de una expresión completa, de los cuales uno es la expresión en una declaración de retorno.
Ya que está devolviendo 42, hay un punto de secuencia inmediatamente después de esa declaración de return
.
Para completar, los puntos de secuencia de C99 se enumeran aquí, con el relevante en negrita:
Los siguientes son los puntos de secuencia descritos en 5.1.2.3:
- La llamada a una función, una vez evaluados los argumentos (6.5.2.2).
- El final del primer operando de los siguientes operadores: lógico AND && (6.5.13); OR lógico || (6.5.14); condicional? (6.5.15); coma, (6.5.17).
- El fin 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 (if o switch) (6.8.4); la expresión de control de la 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 con formato (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 a esa llamada (7.20.5).