C11 aclara la respuesta a esta pregunta, en el proyecto de C11 sección estándar 6.8.5
declaraciones de iteración añade el apartado siguiente:
Una declaración iteración cuya expresión de control no es una constante expresión, 156) que no realiza operaciones de entrada/salida, no accede a objetos volátiles, y no realiza operaciones de sincronización en su cuerpo, control de expresión o (en el caso de para la declaración) su expresión-3, puede ser asumida por la implementación para terminar. 157)
y la nota 157
dice:
Esto tiene por objeto permitir transformaciones del compilador, como la eliminación de bucles vacías incluso cuando terminación no pueden ser probados.
Así que su ejemplo específico:
while(1)
/* noop */;
no es juego limpio para la optimización ya que la expresión de control es una expresión constante.
bucles
infinito como UB
¿Por qué son los compiladores permite optimizar distancia bucles infinitos con la excepción de lo previsto anteriormente, así Hans Boehm proporciona una justificación para hacer bucles infinitos comportamiento indefinido en: N1528: Why undefined behavior for infinite loops?, la siguiente cita da una buena sensación para la edición implicada:
Como N1509 señala correctamente, el actual proyecto da esencialmente comportamiento indefinido a bucles infinitos en 6.8.5p6. Un problema importante para es que permite que el código se mueva a través de un bucle no terminante potencialmente . Por ejemplo, supongamos que tenemos los siguientes bucles, donde recuento y Cont2 son variables globales (o han tenido su dirección de tomada) y P es una variable local, cuya dirección no ha sido tomada:
for (p = q; p != 0; p = p -> next) {
++count;
}
for (p = q; p != 0; p = p -> next) {
++count2;
}
se pudo estos dos bucles se fusionan y se reemplazan por el siguiente bucle?
for (p = q; p != 0; p = p -> next) {
++count;
++count2;
}
Sin la dispensación especial en 6.8.5p6 de bucles infinitos, esto sería no permitidos: Si el primer bucle no termina porque q apunta a una lista circular, el original nunca se escribe en Cont2. Por lo tanto, podría ejecutarse en paralelo con otro subproceso que tenga acceso o actualizaciones count2. Esto ya no es seguro con la versión transformada que accede a count2 a pesar del bucle infinito. Por lo tanto, la transformación potencialmente introduce una carrera de datos.
En casos como este, es muy poco probable que un compilador pueda para probar la terminación del bucle; tendría que entender que q los puntos de a una lista acíclica, que creo que está más allá de la capacidad de la mayoría de los compiladores mainstream, y a menudo imposible sin toda la información del programa .
C99
Desde C99 no tiene esta tallar, miraríamos a la como-si la regla trata en la sección 5.1.2.3
que básicamente dice que el compilador sólo tiene que emular el comportamiento observable de un programa, los requisitos son los siguientes:
los requisitos mínimos en una aplicación conforme son:
- En los puntos de secuencia, los objetos volátiles son estables en el sentido de que los accesos anteriores son completos y los accesos subsiguientes aún no han ocurrido.
- Al finalizar el programa, todos los datos escritos en los archivos deben ser idénticos al resultado que la ejecución del programa según la semántica abstracta hubiera producido .
- La dinámica de entrada y salida de los dispositivos interactivos se realizará como se especifica en 7.19.3. La intención de estos requisitos es que la salida sin buffer o con buffer de línea aparezca tan pronto como sea posible, para garantizar que los mensajes de aviso aparezcan realmente antes de un programa que espera la entrada.
Una lectura estricta de este parecería permitir que una aplicación para optimizar un bucle infinito de distancia. Desde luego, podemos llegar a escenarios en los que la optimización de distancia en un bucle infinito causaría un cambio en la conducta observable:
while(1) ;
printf("hello world\n") ;
Muchos dirán que efectuar la terminación de un proceso es también el comportamiento observable, esta posición se toma en C Compilers Disprove Fermat’s Last Theorem:
el compilador se da una gran libertad en la forma en que implementa el programa en C, pero su producción debe tener el mismo comportamiento visible externamente que el programa tendría si se interpreta por la “máquina abstracta C” que se describe en la norma . Muchas personas conocedoras (incluyéndome a mí) leen esto diciendo que el comportamiento de terminación de un programa no debe cambiarse. Obviamente, algunos escritores de compiladores no están de acuerdo, o de lo contrario no creen que importe. El hecho de que personas razonables no estén de acuerdo con la interpretación parece indicar que el estándar C es defectuoso.
actualización
de alguna manera se perdió el seguimiento con el artículo anterior, Compilers and Termination Revisited que dice lo siguiente acerca de la sección 5.1.2.3
:
El segundo requisito es el asunto difícil.Si se trata de la terminación del programa que se ejecuta en la máquina abstracta, entonces se cumple de manera imprecisa porque nuestro programa no finaliza. Si se trata de la terminación del programa real generado por el compilador, entonces la implementación C tiene errores porque los datos escritos en los archivos (stdout es un archivo) difieren de los datos escritos por la máquina abstracta. (Esta lectura se debe a Hans Boehm, que había dejado de burlarse de esta sutileza fuera de la norma.)
Se podría también hacer un argumento más débil que la necesidad de crear un labrarse en C11 para permitir la remoción de bucle vacío implica que esto no era una optimización permitida previamente.
¿Esto se aplica a infinitos goto loops también?
Creo que la intención es que esto también se aplique a infinitos goto loops también. En C++ esto es claramente el caso desde la sección 1.10
[intro.multithread] dice:
La implementación puede asumir que cualquier tema con el tiempo se lleve a cabo uno de los siguientes
- terminar,
- hacer una llamada a una función de E/S de la biblioteca,
- acceder o modificar un objeto volátil, o
- realizar una operación de sincronización o una en operación ómica
y luego la intención expresada en N1528
es que el C y C++ estándar de acuerdo:
Desde compilador back-ends se comparten típicamente entre los compiladores de C y C++, parece más importante que WG14 y WG21 acuerdan cualquier solución que se adopte. Las alternativas serían un tratamiento especial de los dos idiomas por parte del back-end o deshabilitar las optimizaciones al procesar el código C. Ninguno de los dos parece deseable.
y al final dice:
WG21 está considerando la mejora de redacción que hace que el tratamiento coherente. Es de esperar que WG14 rastree los cambios resultantes.
Actualmente el estándar C11 no contiene el texto similar en la sección 5.1.2.4
ejecuciones multi-hilo y razas de datos pero teniendo en cuenta N1528
parece prudente asumir compiladores tratar infinita bucles Goto comportamiento como indefinido en C y C++.
Tenga en cuenta también ver US comment 38 here y N3196 que es el papel que este cambio se aplicó.
Está ocupado esperando, y los daemons no deben usar ocupado, esperando mucho. Llamo tal construcción "muerta" en el flujo de datos. Si la instrucción no cambia ninguna variable y no contiene efectos secundarios, se puede eliminar optimizando el compilador. – osgx
El código después del bucle no es "inalcanzable", el bucle se puede interrumpir con la señal, y puede haber "longjmp" en el manejador de señal. – osgx
"Optimización de bucles sin fin" == "cómo hacer que bucles interminables terminen más rápido" –