Permettez-moi de vous donner un argument pour expliquer pourquoi je pense que ce n'est toujours pas défini.
Tout d'abord, les répondants disent que c'est "la plupart du temps définies" ou somesuch, basées sur leur expérience avec certains compilateurs, sont tout simplement faux. Une petite modification de votre exemple servira à illustrer:
#include <stdio.h>
int
main()
{
int v;
scanf("%d", &v);
if (v != 0)
{
printf("Hello\n");
int *p;
*p = v; // Oops
}
return v;
}
Ce que ce programme fait-il que si vous fournissez de "1" en entrée? Si la réponse est "Il imprime Bonjour et puis se bloque", vous avez tort. "Un comportement indéfini" ne signifie pas que le comportement de certains aspects spécifiques de la déclaration n'est pas défini; cela signifie que le comportement de l' ensemble du programme n'est pas défini. Le compilateur est permis de supposer que vous ne vous engagez pas dans un comportement indéfini, donc dans ce cas, on peut supposer que l' v
est non-nul, et tout simplement émet pas de code entre crochets à tous, y compris l' printf
.
Si vous pensez que c'est peu probable, détrompez-vous. GCC ne peut pas effectuer cette analyse exactement, mais il le fait très similaires. Mon exemple préféré, qui fait illustre le point pour de vrai:
int test(int x) { return x+1 > x; }
Essayez d'écrire un petit programme de test pour imprimer INT_MAX
, INT_MAX+1
, et test(INT_MAX)
. (Assurez-vous d'activer l'optimisation.) Une implémentation typique pourrait démontrer INT_MAX
à 2147483647, INT_MAX+1
à -2147483648, et test(INT_MAX)
1.
En fait, GCC compile cette fonction pour renvoyer une constante à 1. Pourquoi? En raison de dépassement d'entier est un comportement indéfini, donc le compilateur peut supposer que vous ne le faisons pas, donc x ne peut pas égaler INT_MAX
donc x+1
est plus grand que x
, donc cette fonction peut renvoyer 1 inconditionnellement.
Un comportement indéfini, peut entraîner des variables qui ne sont pas égaux à eux-mêmes, les nombres négatifs qui comparent de plus que des nombres positifs (voir l'exemple ci-dessus), et d'autres comportements bizarres. Le plus intelligent le compilateur, le plus bizarre le comportement.
OK, je l'avoue, je ne peux pas citer le chapitre et le verset de la norme afin de répondre à la question exacte que vous avez demandé. Mais les gens qui disent "Ouais ouais, mais dans la vraie vie déréférencement NULL donne juste un seg fault" sont de plus mal que ce qu'ils peuvent imaginer, et ils obtiennent plus de mal avec chaque compilateur génération.
Et dans la vraie vie, si le code est morte, vous devriez le retirer; si elle n'est pas morte, vous ne devez pas appeler un comportement indéfini. Voilà donc ma réponse à votre question.