Est-ce que ((void*)0) est une constante de pointeur nulle?

je lis ce billet de blog et sous la rubrique constantes de point nul et expressions entre parenthèses l'auteur renvoie aux paragraphes 6.3.2.3 et 6.5.1 de la norme ISO C et dit:

Il n'est pas dire qu'une mise entre parenthèses de pointeur null constante est un pointeur null constante.

qui implique, à proprement parler, que (void*)0 est un pointeur null constante, mais ((void*)0) ne l'est pas.

puis:

je suis sûr que la plupart des implémentations C traitent une constante de pointeur nulle entre parenthèses comme une constante de pointeur nulle, et définissent NULL soit comme 0 , ((void*)0) , ou d'une autre manière.

les deux sections référencées disent:

§ 6.3.2.3

une expression constante entière avec la valeur 0, ou une telle expression cast to type void *, s'appelle une constante de pointeur nulle.

§ 6.5.1

une expression entre parenthèses est une expression primaire. son type et sa valeur sont identiques à ceux de l'expression sans équivalent. c'est un lvalue, un désignateur de fonction, ou une expression de vide si l'expression sans équivalent est, respectivement, une lvalue, une fonction indicateur, ou une expression de vide.

la phrase en caractères gras ne contredit-elle pas l'affirmation de l'auteur selon laquelle ((void*)0) n'est pas une constante de pointeur nulle?

31
demandé sur user4164058 2014-10-21 04:41:42

2 réponses

la phrase en caractères gras ne contredit-elle pas l'affirmation de l'auteur selon laquelle ((void*)0) n'est pas une constante de pointeur nulle?

Non. (J'avoue être un peu partial, puisque le blog référencé est le mien.)

la phrase en caractères gras indique que ses type et valeur sont identiques à celles de l'expression sans équivalent. Ce n'est pas assez à entendre que c'est une constante de pointeur nulle.

prendre en considération:

void *var = 0;

(void*)0 est une constante de pointeur nulle. ((void*)0) a le même type et la même valeur que (void*)0 . var aussi a le même type et la même valeur que (void*)0 , mais var n'est clairement pas une constante de pointeur nulle.

ayant dit cela, je suis sûr à 99+% que le intention est que ((void*)0) est un constante de pointeur nulle, et plus généralement que toute constante de pointeur nulle entre parenthèses est une constante de pointeur nulle. Les auteurs de la norme simplement négligé de le dire. Et depuis la description des expressions entre parenthèses dans 6.5.1p5 énumère spécifiquement plusieurs autres caractéristiques héritées des expressions entre parenthèses:

une expression entre parenthèses est une expression primaire. Son type et sa valeur sont identiques à ceux de la sans parenthèse expression. C'est un lvalue, un désignateur de fonction, ou une expression de vide si l'expression sans équivalent est, respectivement, une valeur l, une fonction indicateur, ou une expression de vide.

l'omission est troublante (mais seulement légèrement).

mais supposons, pour les besoins de l'argument, que ((void*)0) n'est pas une constante de pointeur nulle. Quelle différence cela fait-il?

(void*)0 est un constante de pointeur nulle, dont la valeur est un pointeur nul de type void* , donc par la sémantique des expressions entre parenthèses ((void*)0) a également une valeur qui est un pointeur nul de type void* . Les deux (void*)0 et ((void*)0) sont constantes d'adresse . (Eh bien, je pense ils sont.) Alors, quels contextes nécessitent une constante de pointeur et n'acceptent pas une constante d'adresse ? Y ne sont que quelques-uns.

6.5.9 opérateurs d'Égalité

une expression de type pointeur de fonction peut être comparée pour l'égalité à une constante de pointeur nulle. (Un pointeur d'objet peut être comparé à une expression de type void* , mais un pointeur de fonction ne peut pas, sauf s'il s'agit d'une constante de pointeur nulle.) Ainsi:

void func(void);
if (func == ((void*)0)) { /* ... */ }

serait une violation de contrainte.

6.5.16.1 Simple assignment

dans une tâche, une constante de pointeur nulle peut être assignée à un objet de type pointeur-à-fonction, et sera convertie implicitement. Une expression de type void* qui n'est pas une constante de pointeur nulle ne peut pas être assignée à un pointeur de fonction. Les mêmes contraintes s'appliquent au passage d'arguments et à l'initialisation. Ainsi:

void (*fp)(void) = ((void*)0);

serait une violation de contrainte si ((void*)0) n'était pas une constante de pointeur nulle. Merci au commentateur hvd pour trouver cet.

7.19 définitions communes <stddef.h>

La macro NULL étend "à la mise en œuvre définies par pointeur null constante". Si ((void*)0) n'est pas une constante de pointeur nulle, alors ceci:

#define NULL ((void*)0)

serait invalide. Il s'agirait d'une restriction imposée à la mise en oeuvre, et non aux programmeurs. Notez que ceci:

#define NULL (void*)0

est définitivement invalide, puisque macro les définitions dans les en-têtes standards doivent être entièrement protégées par des parenthèses si nécessaire (7.1.2p5). Sans les parenthèses, l'expression valide sizeof NULL serait une erreur de syntaxe, s'étendant à sizeof (void*) suivi d'une constante étrangère 0 .

25
répondu Keith Thompson 2017-08-13 19:55:52

c'est une expression entre parenthèses qui contient une constante de pointeur nulle, donc elle est indiscutablement une valeur de pointeur nulle. L'utiliser comme valeur de r a exactement le même effet que d'utiliser la version "conforme" comme valeur de R.

S'il y avait des règles syntaxiques qui pourraient seulement accepter une constante de pointeur nulle, il ne serait pas admissible. Mais je n'en connais pas (bien que je sois moins expert en C).

et bien que ni l'un ni l'autre ne soit constante (se référant à la production grammaticale formelle), les deux peuvent apparaître dans une expression constante dans un initialiseur, parce que les constantes nulles de pointeur et les constantes d'adresse sont permises, et une valeur nulle constante de pointeur est explicitement incluse dans la catégorie de constante d'adresse .

Les comparaisons de pointeurs

mentionnent aussi spécifiquement les constantes nulles de pointeur... mais ici, les valeurs de pointeur sont également acceptées, et tous pointeur null les valeurs sont traitées de la même manière. Idem pour les opérateurs ternaires et les opérateurs d'affectation.

veuillez noter que ces règles sont très différentes en C++, où les deux expressions ci-dessus sont des valeurs de pointeur nulles constantes de type void* , mais pas des constantes de pointeur nulles universelles. Les constantes de pointeur nulles en C++ sont des expressions de constante intégrale qui s'évaluent à zéro. Et void* ne convertit pas implicitement en d'autres types de pointeurs.

6
répondu Ben Voigt 2014-10-21 01:30:26