C'est l'un de ces cas étranges où nous sommes soumis aux limitations de la langue anglaise et à la structure incohérente de la norme. Donc, au mieux, je peux faire un contre-argument convaincant, car il est impossible de le prouver :) 1
Le code de la question présente un comportement bien défini.
Comme [7.1.4] est la base de la question, commençons par là:
Chacune des instructions suivantes s'applique, sauf indication contraire explicite dans les descriptions détaillées qui suivent: Si un argument d'une fonction a une valeur non valide ( telle qu'une valeur en dehors du domaine de la fonction, ou un pointeur en dehors de l'espace d'adressage du programme, ou un pointeur nul , [... autres exemples ...] ) [...] le comportement n'est pas défini. [... autres déclarations ...]
C'est un langage maladroit. Une interprétation est que les éléments de la liste sont UB pour toutes les fonctions de la bibliothèque, à moins qu'ils ne soient remplacés par les descriptions individuelles. Mais la liste commence par "comme", indiquant que c'est illustratif et non exhaustif. Par exemple, il ne mentionne pas la terminaison nulle correcte des chaînes (critique pour le comportement de par exemple strcpy
).
Il est donc clair que l'intention / la portée de 7.1.4 est simplement qu'une "valeur invalide" mène à UB ( sauf indication contraire ). Nous devons examiner la description de chaque fonction pour déterminer ce qui compte comme "valeur invalide".
Exemple 1 - strcpy
[7.21.2.3] dit seulement ceci:
La strcpy
fonction copie la chaîne pointée par s2
(y compris le caractère nul de fin) dans le tableau pointé par s1
. Si la copie a lieu entre des objets qui se chevauchent, le comportement n'est pas défini.
Il ne fait aucune mention explicite des pointeurs nuls, mais il ne fait pas non plus mention des terminateurs nuls. Au lieu de cela, on déduit de "chaîne pointée par s2
" que les seules valeurs valides sont des chaînes (c'est-à-dire des pointeurs vers des tableaux de caractères terminés par un nul).
En effet, ce modèle peut être vu à travers les descriptions individuelles. Quelques autres exemples:
[7.6.4.1 (fenv)] stocke l'environnement en virgule flottante actuel dans l' objet pointé parenvp
[7.12.6.4 (frexp)] stocke l'entier dans l' objet int pointé parexp
[7.19.5.1 (fclose)] le flux pointé parstream
Exemple 2 - printf
[7.19.6.1] dit ceci à propos de %p
:
p
- L'argument doit être un pointeur vers void
. La valeur du pointeur est convertie en une séquence de caractères d'impression, d'une manière définie par l'implémentation.
Null est une valeur de pointeur valide, et cette section ne fait aucune mention explicite que null est un cas particulier, ni que le pointeur doit pointer sur un objet. C'est donc un comportement défini.
1. À moins qu'un auteur de normes ne se présente, ou à moins que nous puissions trouver quelque chose de similaire à un document de justification qui clarifie les choses.