Variable non initialisée en C

Je suis un peu confuse. Autant que je sache, si vous déclarez un int en C, sans l’initialiser, par exemple: int x;

sa valeur est donc indéterminée. Donc, si nous essayons de l’utiliser ou si nous devrions avoir un comportement indéfini.

Donc, si j’utilise le code suivant dans VS2010, le programme est bloqué.

 int main(){ int a; printf("%d\n",a); return 0; } 

Regardons maintenant le code suivant, qui ne fournit aucun avertissement et ne plante pas (pourquoi?)

 void foo(int *var_handle){ // do nothing } int main(){ int a; foo(&a); printf("%d\n",a); // works, prints some big value return 0; } 

Pouvez-vous expliquer le comportement de cela? nous avons seulement ajouté un appel à une fonction qui ne fait rien du tout, mais maintenant, le programme ne plante pas.

La lecture de la valeur d’une variable non initialisée entraîne un comportement indéfini. Et un comportement non défini signifie qu’il peut tomber en panne. Cela ne veut pas dire que ça va ou il est obligé de planter.

Une variable non initialisée a une valeur non spécifiée. On ignore simplement quelle est sa valeur. Donc, dans la pratique, avec toute implémentation rationnelle, ce type de code ne plantera probablement jamais. Il y a une adresse mémoire valide sauvegardant la variable, elle a un contenu printf() , printf() lit sans problème, l’interprète comme un entier et l’imprime, c’est tout.

L’utilisation d’une valeur non initialisée ne provoque pas directement un comportement non défini.

Par C 2011 (version n1570) 6.7.9 10, un object non initialisé avec une durée de stockage automatique a une valeur indéterminée. Selon 3.19.2 1, une valeur indéterminée est soit une valeur non spécifiée, soit une représentation de piège. Un texte similaire apparaît dans la lettre C 1999.

Si l’object a une représentation d’interruption, un comportement non défini peut se produire. Cependant, si l’object a une valeur non spécifiée, alors le programme doit se comporter comme si l’object avait une valeur déterminée; il n’est simplement pas spécifié quelle valeur a l’object. Le programme n’est pas autorisé à se bloquer simplement parce que la valeur n’est pas spécifiée.

Il est surprenant que vous signaliez des plantages du programme simple affichés dans Visual Studio 2010, car je ne m’attends pas à ce que le type int ait des représentations d’interruption dans Visual Studio 2010. Il se peut qu’un fichier source autre que celui que vous attendiez ait été compilé et planté ou que vous avez activé des fonctionnalités spéciales de débogage dans Visual Studio 2010 qui tentent de suivre des objects non initialisés (mais échouent dans le second cas où vous utilisez foo ).

Je vous suggère de répéter le test à partir de zéro, en collant le code que vous avez affiché dans cette question dans un nouveau fichier et en compilant ce nouveau fichier avec les options par défaut.

Bien entendu, Visual Studio 2010 n’est pas conforme à la norme C, pas même à l’ancienne norme de 1999, de sorte qu’il n’est pas tenu d’obéir aux clauses ci-dessus. En fait, tout ce qui concerne Visual Studio 2010 correspond à un comportement non défini par rapport à la norme C.

C’est un comportement indéfini , ce qui signifie que tout peut arriver. Littéralement n’importe quoi. Le comportement n’est simplement pas défini.

Vous pouvez essayer ceci. Je ne sais pas s’il s’agit d’un comportement ssortingctement indéfini ou non, mais je ne vois pas comment un compilateur pourrait se comporter de manière indéfinie tout en restant conforme à la norme C, du moins si foo est dans une unité de compilation différente ( ~ fichier source), car le compilateur ignore alors qu’il est autorisé à produire un comportement indéfini;).

 void foo(int *var_handle){ // do something to var_handle, or maybe nothing, who knows } int main(){ int a[1]; foo(a); printf("%d\n", a[0]); return 0; } 

Edit: Autres pensées:

Je suis presque certain que l’utilisation d’une fonction pour initialiser une variable locale non initialisée est acceptable, en donnant un pointeur non-const à la variable locale vers la fonction. Donc, obtenir simplement l’adresse d’une variable locale la rend une variable définie avec une valeur indéfinie, en ce qui concerne le compilateur. Le compilateur ne peut pas savoir si la fonction définit réellement la valeur ou non (la fonction peut être dans une bibliothèque).

Mais cela explique simplement pourquoi cela évite le crash. Il se pourrait que si la fonction est autorisée à être alignée et qu’elle ne fasse rien, l’optimiseur serait autorisé à supprimer l’appel, puis également à supprimer l’adresse de prise de la variable locale non initialisée, la laissant ainsi dans l’état “comportement non défini”. Vous pouvez tester cela pour votre compilateur en activant des optimisations et en vérifiant, à partir de la sortie de l’assembly, que l’appel à foo est en ligne (ne produisant aucun code), et voir si printf se bloque alors.

Rien ne garantit que l’utilisation d’une variable non initialisée provoquera le blocage de votre programme. Cela dépend des données indésirables stockées dans l’emplacement mémoire atsortingbué à la variable.