Un appel scanf non vérifié peut-il provoquer un comportement non défini?

L’extrait de code ci-dessous invoque-t-il un comportement indéfini en cas d’erreur?

#include  int main() { int i; /* Indeterminate */ if (scanf("%d", &i) == 1) /* Initialize */ printf("%d\n", i); /* Success! Print read value */ else printf("%d\n", i); /* Input failed! Is printing `i` UB or not? */ return 0; } 

Que se passe-t-il si scanf échoue? Une variable non initialisée est-elle utilisée?

MODIFIER
De plus, si je remplace scanf("%d", &i) par my_initializer(&i) :

 int my_initializer(int *pi) { double room_temp_degc = get_room_temp_in_degc(); if(room_temp_degc < 12.0) { // Cool *pi = 42; return 1; } else { return 0; } } 

En C90, c’est UB.

Techniquement, ce n’est pas le cas pour C99 et C11, mais la sortie est indéterminée. Il est même possible qu’un autre printf suivant directement imprime une valeur différente; les variables non initialisées peuvent sembler changer sans action explicite du programme. Notez cependant qu’une variable non initialisée ne peut être lue que si son adresse a été prise *) (ce qui est fait ici dans l’appel scanf ). À partir de n1570 6.3.2.1 p2:

Si la lvalue désigne un object de durée de stockage automatique qui aurait pu être déclaré avec la classe de stockage register (son adresse n’a jamais été prise) et que cet object est non initialisé (non déclaré avec un initialiseur et qu’aucune affectation n’a été effectuée avant son utilisation. ), le comportement est indéfini.

En théorie , cela permettrait quelque chose comme

 int n; &n; printf("%d\n", n); 

Toutefois, les compilateurs peuvent toujours réordonner les instructions ou allouer des registres en supposant que la première lecture ne se produit pas avant la première écriture et ignorer les effets secondaires free &n; déclaration.

Pour des raisons pratiques, ne jamais lire les valeurs non initialisées. Premièrement, il n’y a aucune raison pour laquelle vous devriez vouloir; deuxièmement, même une valeur non spécifiée permet d’optimiser les optimisations: certains pensaient qu’une valeur “garbage” pourrait être utilisée pour rassembler une entropie pour des nombres aléatoires, ce qui conduirait à de très mauvais bogues dans les logiciels cryptographiques, voir par exemple l’entrée de blog de Xi Wang . Pour un exemple encore plus complexe, où une valeur non initialisée est impair après une multiplication par 2, voir par exemple ce blog (oui, indéterminé fois 2 est simplement indéterminé, pas et autrement indéterminé).

Voir aussi DR 260 .

*) Le paragraphe cité est manquant dans C99, mais cela devrait être considéré comme un défaut de la norme, pas comme une modification de C11. C99 le définit techniquement (pour les machines sans représentations d’interruption) à lire toute variable non initialisée (bien que leurs valeurs soient toujours indéterminées et puissent sembler toujours changer de manière aléatoire, ce n’est tout simplement pas UB).

Avec DR 338 , cela a été corrigé, mais pas avant C11. Il a été ajouté pour autoriser NaT sur une plate-forme Titanium (qui existe pour les registres, mais pas pour les valeurs en mémoire), même pour les types entiers sans représentations d’interruptions. Je ne sais pas si le &n dans le code ci-dessus a un effet sur une telle plate-forme (à la lecture ssortingcte de C11, il devrait, mais je ne le ferais pas).