¿Se define el comportamiento de un programa que tiene un comportamiento indefinido en una ruta inalcanzable?
language-lawyer undefined-behavior (3)
Esta pregunta ya tiene una respuesta aquí:
Considerar
void swap(int* a, int* b)
{
if (a != b){
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
}
int main()
{
int a = 0;
int b = 1;
swap(&a, &b); // after this b is 0 and a is 1
return a > b ? 0 : a / b;
}
swap
es un intento de engañar al compilador para que no optimice el programa.
¿Está definido el comportamiento de este programa? a / b
nunca es alcanzable, pero si lo fuera, obtendrías una división por cero.
El comportamiento de una expresión que no se evalúa es irrelevante para el comportamiento de un programa. El comportamiento que sería indefinido si la expresión fuera evaluada no tiene relación con el comportamiento del programa.
Si lo hiciera, entonces este código sería inútil:
if (p != NULL)
…; // Use pointer p.
(Sus XOR pueden tener un comportamiento indefinido, ya que pueden producir una representación de trampa. Puede anular la optimización para ejemplos académicos como este declarando que un objeto es volátil. Si un objeto es volátil, la implementación de C no puede saber si su valor puede cambiar debido a medios externos, por lo que cada uso del objeto requiere que la implementación lea su valor.)
En general, el código que invocaría un comportamiento indefinido si se ejecutara no debería tener ningún efecto si no se ejecuta. Sin embargo, existen algunos casos en los que las implementaciones del mundo real pueden comportarse de manera contraria y se niegan a generar código que, si bien no es una violación de restricción, no podría ejecutarse en un comportamiento definido.
extern struct foo z;
int main(int argc, char **argv)
{
if (argc > 2) z;
return 0;
}
Al leer el Estándar, caracteriza explícitamente las conversiones de valores de valores en tipos incompletos como invocando un comportamiento indefinido (entre otras cosas, no está claro qué es lo que una implementación podría generar código para tal cosa), por lo que el estándar no impondría requisitos sobre el comportamiento si argc
es 3 o más. Sin embargo, no puedo identificar ninguna restricción en la Norma que el código anterior violaría, ni ninguna razón por la cual el comportamiento no debería definirse completamente si argc
es 2 o menos. No obstante, muchos compiladores, incluidos gcc y clang, rechazan por completo el código anterior.
No es necesario basar una posición en esta pregunta en la utilidad de cualquier construcción o práctica de código dada, ni en nada escrito sobre C ++, ya sea en su respuesta estándar o en otra SO, sin importar qué tan similares puedan ser las definiciones de C ++. La clave a considerar es la definición de comportamiento indefinido de C :
comportamiento, en el uso de un constructo de programa no portátil o erróneo o de datos erróneos, para los cuales esta Norma Internacional no impone requisitos
(C2011, 3.4.3 / 1; énfasis añadido)
Por lo tanto, el comportamiento indefinido se desencadena temporalmente ("en uso" de una construcción o datos), no por mera presencia. * Es conveniente que esto sea coherente para el comportamiento indefinido que surge de los datos y el que surge de las construcciones del programa; el estándar no tiene que haber sido consistente allí. Y como lo describe otra respuesta, esta definición "en uso" es una buena opción de diseño, ya que permite a los programas evitar la ejecución de comportamientos indefinidos asociados con datos erróneos.
Por otro lado, si un programa ejecuta un comportamiento indefinido, de la definición estándar se desprende que todo el comportamiento del programa no está definido. Esta indefinición consecuente es un tipo más general que surge del hecho de que la UB asociada directamente con los datos o construcciones erróneas podría, en principio, incluir alterar el comportamiento de otras partes del programa, incluso de forma retroactiva (o aparentemente). Por supuesto, hay limitaciones extra-linguales en lo que podría suceder, así que no, los demonios nasales no harán ninguna aparición, pero no son necesariamente tan fuertes como se podría suponer.
* Advertencia: algunas construcciones de programas se utilizan en el momento de la traducción. Estos producen UB en la traducción del programa, con el resultado de que cada ejecución del programa tiene un comportamiento totalmente indefinido. Para un ejemplo un tanto estúpido, si la fuente de su programa no termina con una nueva línea no escapada, entonces el comportamiento del programa es completamente indefinido (ver C2011, 5.1.1.2/1 , punto 2).