web-dev-qa-db-fra.com

((Void *) 0) est-il une constante de pointeur nul?

Je lis cet article de blog et sous la section Constantes de pointeur nul et expressions entre parenthèses l'auteur fait référence au § 6.3.2.3 et § 6.5.1 de la norme ISO C et dit:

Il ne fait pas dire qu'une constante de pointeur nul entre parenthèses est une constante de pointeur nulle.

Ce qui implique, à proprement parler, que (void*)0 est une constante de pointeur nul, mais ((void*)0) n'est pas.

Ensuite:

Je suis sûr que la plupart des implémentations C traitent une constante de pointeur nul entre parenthèses comme une constante de pointeur nul 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 de constante entière avec la valeur 0, ou une telle expression transtypée pour taper void *, est appelée une constante de pointeur nul.

§ 6.5.1

Une expression entre parenthèses est une expression principale. Son type et sa valeur sont identiques à ceux de l'expression non entre parenthèses. Il s'agit d'une valeur l, d'un désignateur de fonction ou d'une expression vide si l'expression non parenthèse est, respectivement, une valeur l, un désignateur de fonction ou une expression void.

La phrase en gras ne contredit-elle pas l'affirmation de l'auteur selon laquelle ((void*)0) n'est pas une constante de pointeur nul?

34
user4164058

La phrase en gras ne contredit-elle pas l'affirmation de l'auteur selon laquelle ((void*)0) N'est pas une constante de pointeur nul?

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

La phrase en gras indique que ses type et valeur sont identiques à ceux de l'expression non entre parenthèses. Cela ne suffit pas pour impliquer qu'il s'agit d'une constante de pointeur nul.

Considérer:

void *var = 0;

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

Cela dit, je suis sûr à 99 +% que intention est que ((void*)0) Est une constante de pointeur nul, et plus généralement que toute constante de pointeur nul entre parenthèses est une constante de pointeur nul. Les auteurs de la norme ont simplement négligé de le dire. Et puisque 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 principale. Son type et sa valeur sont identiques à ceux de l'expression non entre parenthèses. Il s'agit d'une valeur l, d'un indicateur de fonction ou d'une expression vide si l'expression non entre parenthèses est, respectivement, une valeur l, un indicateur de fonction ou une expression 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 nul. Quelle différence cela fait?

(void*)0 Est une constante de pointeur nul, 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 tapez void*. (void*)0 Et ((void*)0) Sont tous les deux constantes d'adresse. (Eh bien, je pense ils le sont.) Alors, quels contextes nécessitent une constante de pointeur nul et n'acceptent pas une constante d'adresse? Il n'y en a que quelques-uns.

6.5.9 Opérateurs d'égalité

Une expression de type pointeur de fonction peut être comparée pour son égalité à une constante de pointeur nulle. (Un pointeur d'objet peut être comparé à une expression de type void*, Mais pas un pointeur de fonction, sauf s'il s'agit d'une constante de pointeur nulle.) Donc ceci:

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

serait une violation de contrainte.

6.5.16.1 Affectation simple

Dans une affectation, une constante de pointeur nul peut être affectée à un objet de type pointeur vers fonction et sera implicitement convertie. Une expression de type void* Qui n'est pas une constante de pointeur nul ne peut pas être affectée à un pointeur de fonction. Les mêmes contraintes s'appliquent au passage d'arguments et à l'initialisation. Donc ça:

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

serait une violation de contrainte si ((void*)0) n'était pas une constante de pointeur nul. Merci au commentateur hvd de l'avoir trouvé.

7.19 Définitions communes <stddef.h>

La macro NULL se développe en "une constante de pointeur nul définie par l'implémentation". Si ((void*)0) N'est pas une constante de pointeur nulle, alors ceci:

#define NULL ((void*)0)

serait invalide. Ce serait une restriction imposée à l'implémentation, pas aux programmeurs. Notez que ceci:

#define NULL (void*)0

est définitivement invalide, car les définitions de macro dans les en-têtes standard 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*) suivie d'une constante étrangère 0.

28
Keith Thompson

Il s'agit d'une expression entre parenthèses qui contient une constante de pointeur null, il s'agit donc incontestablement d'une valeur de pointeur null. Son utilisation en tant que valeur r a exactement le même effet que l'utilisation de la version "conforme" comme valeur r.

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

Et tandis que ni l'un ni l'autre n'est une constante (se référant à la production de grammaire formelle), les deux peuvent apparaître dans une expression constante dans un initialiseur, car les deux constantes de pointeur nul et les constantes d'adresse sont autorisées, et une valeur de pointeur nul constante est explicitement incluse dans la catégorie de constante d'adresse .

Les comparaisons de pointeurs mentionnent également spécifiquement les constantes de pointeur nul ... mais ici, les valeurs de pointeur sont également acceptées et toutes les valeurs de pointeur nul sont traitées de manière égale. Idem pour les opérateurs ternaires et 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 nul constantes de type void*, mais pas les constantes de pointeur nul universelles. Les constantes de pointeur nul en C++ sont expressions constantes intégrales qui s'évaluent à zéro. Et void* ne se convertit pas implicitement en d'autres types de pointeurs.

7
Ben Voigt