6

Considere el siguiente programa C:¿Está especificado el comportamiento de i = post_increment_i(), no especificado o indefinido?

int i = 0; 

int post_increment_i() { return i++; } 

int main() { 
    i = post_increment_i(); 
    return i; 
} 

Con respecto a la versión 2011 de la norma C (conocido como C11), ¿cuál de las siguientes alternativas es cierto:

  1. C11 garantiza que los retornos principales 0.
  2. C11 garantiza que la devolución principal sea 0 o 1.
  3. El comportamiento de este programa no está definido de acuerdo con C11.

fragmentos relevantes de la norma C11:

  • 5.1.2.3 Ejecución del programa

    Acceso a un objeto volátil, la modificación de un objeto, la modificación de un archivo, o llamar a una función que ¿Alguna de esas operaciones son todos efectos secundarios, que son cambios en el estado de del entorno de ejecución? La evaluación de una expresión en general incluye cálculos de valor y el inicio de efectos secundarios. El cálculo del valor para una expresión lvalue incluye la determinación de la identidad del objeto designado.

    Secuencial anterior es una relación asimétrica, transitiva, por pares, entre las evaluaciones ejecutada por un único hilo, lo que induce un orden parcial entre esas evaluaciones. Dadas dos evaluaciones A y B, si A se secuencia antes de B, entonces la ejecución de A debe preceder a la ejecución de B. (A la inversa, si A se secuencia antes de B, entonces B es secuenciada después de A.) Si A no está secuenciado antes o después de B, entonces A y B son no secuenciados. Las evaluaciones A y B se secuencian indefinidamente cuando A se secuencia antes o después de B, pero no se especifica qué. La presencia de un punto de secuencia entre la evaluación de las expresiones A y B implica que cada cómputo de valor y efecto secundario asociado con A se secuencia antes de cada cómputo de valor y efecto secundario asociado con B. (Un resumen de la secuencia puntos se da en el anexo C.)

    13) Las ejecuciones de evaluaciones no secuenciadas pueden intercalarse. Las evaluaciones secuenciadas indefinidamente no pueden intercalarse, pero se pueden ejecutar en cualquier orden.

  • 6.5 Expresiones

    Una expresión es una secuencia de operadores y operandos que especifica el cálculo de un valor , o que designa un objeto o una función, o que genera efectos secundarios, o que realiza una combinación de eso. Los cómputos de valores de los operandos de un operador se ordenan antes del cálculo del valor del resultado del operador.

    Si un efecto secundario en un objeto de escalar es unsequenced con relación a ya sea un efecto secundario diferente en el mismo objeto escalar o un cálculo de valor usando el valor del mismo objeto escalar , el comportamiento es indefinido. Si hay varias ordenaciones permitidas de las subexpresiones de una expresión, el comportamiento no está definido si se produce un efecto de ese lado no secuenciado en cualquiera de los pedidos.

  • 6.5.2.2 Función llama

    Hay un punto de secuencia después de las evaluaciones del designador de función y los argumentos reales pero antes de la llamada real. Cada evaluación en la función de llamada (incluyendo otras llamadas a función) que no está secuenciada específicamente antes o después de la ejecución del cuerpo de la función llamada se secuencia indeterminadamente con respecto a la ejecución de la función llamada.

    94) En otras palabras, las ejecuciones de funciones no se "entrelazan" entre sí.

  • 6.5.2.4 Postfix de incremento y decremento operadores

    El resultado de la postfix ++ operador es el valor del operando. Como efecto secundario, el valor del objeto operando se incrementa (es decir, se le agrega el valor 1 del tipo apropiado es ). [...] El cálculo del valor del resultado se secuencia antes del efecto secundario de actualizando el valor almacenado del operando. Con respecto a una llamada de función de secuencia indeterminada, la operación de postfix ++ es una evaluación única.

  • 6.5.16 de misiones

    una asignación de operador almacena un valor en el objeto designado por el operando de la izquierda. [...] El efecto secundario de actualizar el valor almacenado del operando izquierdo es secuenciado después de los cálculos del valor de los operandos izquierdo y derecho. Las evaluaciones de los operandos no son secuenciados.

  • 6,8 declaraciones y bloques

    A plena expresión es una expresión que no es parte de otra expresión o de un declarador. Cada una de las siguientes es una expresión completa: [...] la expresión en una declaración de expresión; [...] la expresión (opcional) en una declaración de devolución . Hay un punto de secuencia entre la evaluación de una expresión completa y la evaluación de la siguiente expresión completa a evaluar.

Los tres alternativas anteriores corresponden a los siguientes tres casos, respectivamente:

  1. El efecto secundario de la operador de incremento postfix se secuencia antes de la asignación en el principal.
  2. El efecto secundario del operador de incremento postfix se secuencia antes o después de la asignación en main, y C11 no especifica cuál. (En otras palabras, los dos efectos secundarios están secuenciados indefinidamente).
  3. Los dos efectos secundarios no se han secuenciado.

Parece que la primera alternativa se mantiene, por la siguiente cadena de razonamiento:

  • consideran la Regla Cada evaluación de la función de llamada (incluyendo otros llamadas de función) que no es otra cosa específicamente secuenciado antes o después de la ejecución del cuerpo de la función llamada se secuencia indeterminadamente con respecto a la ejecución de la función llamada. en 6.5.2.2. Supuesto A: El efecto secundario del operador de asignación en main es tal "evaluación". Hipótesis B: la frase "la ejecución de la función llamada" incluye tanto el cálculo del valor del operador de incremento de posfijo como el efecto secundario del operador de incremento de postfijo. A partir de estas suposiciones y la regla anterior, se deduce que o bien I) el cómputo de valor y el efecto secundario del operador de incremento de posfijo se secuencian antes del efecto secundario del operador de asignación en principal, o II) el cómputo de valor y el efecto secundario del operador de incremento postfix son ambos secuenciados después del efecto secundario del operador de asignación en main.

  • Considere la regla El efecto secundario de actualizar el valor almacenado del operando izquierdo es secuenciado después de los cálculos del valor de los operandos izquierdo y derecho. Esta regla descarta el caso I anterior. De esto se sigue que el caso II es válido. QED

En general, esto parece ser un argumento bastante fuerte. Además, corresponde a lo que uno consideraría intuitivamente la alternativa más probable.

Sin embargo, se basa en interpretaciones específicas de los términos "evaluación" y "ejecución de la función llamada" (supuestos A y B) y una línea de razonamiento no del todo directa, así que quise ponerlo allí para ver si las personas tienen razones para creer que esta interpretación es incorrecta. Obsérvese que la nota al pie 94 es equivalente con esta interpretación solo si se aplica también en el sentido de que la persona que llama no se intercala con el destinatario, lo que a su vez implica que "entrelazado" significa entrelazado en el sentido "abab", ya que obviamente una persona intercala con el llamado en el sentido más débil de "aba". Además, las alternativas 2 y 3 parecen plausibles en un escenario donde el compilador inscribe la función y luego realiza los mismos tipos de optimizaciones que motivan por qué la expresión i = i++ tiene un comportamiento indefinido.

+0

pas de probleme. – wildplasser

Respuesta

11

[Mi respuesta se basa en el estándar C99 más simple, y el hecho de que es muy poco probable que C11 introduciría un cambio importante:]

Este comportamiento de este código está bien definida: main vuelve 0 .Hay un punto de secuencia inmediatamente después de la expresión completa en la instrucción return (ver C99, Anexo C), por lo que los efectos secundarios de i++ entran en vigencia antes de la asignación a i en main.

+0

Gracias por esta respuesta bastante satisfactoria. A pesar de que el tratamiento de la secuencia en C99 en general es mucho menos elaborado y más implícito que en C11, para este ejemplo es en realidad más explícito; Estoy de acuerdo en que sería muy difícil interpretar C99 de manera tal que no garantice que los retornos principales 0. – user1480833

Cuestiones relacionadas