D'autres personnes ont expliqué que ce code est parfaitement valide. Cette réponse est sur votre vœu que, si le code était invalide, il y aurait eu une erreur d'exécution lors de l'appel d' printf
. Il n'est pas nécessairement le cas.
Regardons cette variation sur votre code, ce qui est invalide:
#include <stdio.h>
int main(void)
{
int *a;
{
int b = 42;
a = &b;
}
printf("%d\n", *a); // undefined behavior
return 0;
}
Ce programme a un comportement indéfini, mais il arrive à être assez probable qu'il y aura, en fait, d'impression 42, pour plusieurs raisons différentes - de nombreux compilateurs laisser la pile fente b
alloué pour l'ensemble du corps de l' main
, parce que rien d'autre n'a besoin de l'espace et de réduire au minimum le nombre de pile ajustements simplifie la génération de code; même si le compilateur n'a officiellement libérer le logement de la pile, le nombre 42 probablement reste en mémoire jusqu'à ce que quelque chose d'autre la remplace, et il n'y a rien entre les deux, a = &b
et *a
à le faire; norme optimisations ("constant et copie de propagation") pourrait éliminer à la fois les variables et écrire la dernière valeur connue de *a
directement dans l' printf
déclaration (comme si vous l'aviez écrit, printf("%d\n", 42)
).
Il est absolument essentiel de comprendre que le "comportement indéfini" ne signifie pas "le programme va planter prévisible". Il signifie "tout peut arriver", et tout ce qui comprend apparaissant à travailler en tant que programmeur probablement prévu (sur cet ordinateur, avec ce compilateur, aujourd'hui).
Comme note finale, aucun des agressifs, des outils de débogage, j'ai un accès pratique à (Valgrind, ASan, UBSan) piste "auto", la variable de la durée de vie de façon suffisamment détaillée pour intercepter cette erreur, mais GCC 6 ne produire cet amusant d'avertissement:
$ gcc -std=c11 -O2 -W -Wall -pedantic test.c
test.c: In function ‘main':
test.c:9:5: warning: ‘b' is used uninitialized in this function
printf("%d\n", *a); // undefined behavior
^~~~~~~~~~~~~~~~~~
Je crois que ce qui s'est passé ici était, il a fait de l'optimisation que j'ai décrit ci-dessus - la copie de la dernière valeur connue de l' b
en *a
, puis dans l' printf
- , mais sa "dernière valeur connue" pour b
était une "cette variable est initialisée" sentinelle plutôt que de 42. (Puis, il génère un code équivalent à printf("%d\n", 0)
.)