En C, il existe un, et un seul, contexte dans lequel il est nécessaire de convertir explicitement une constante de type pointeur nul en un type de pointeur spécifique pour que le programme fonctionne correctement. Ce contexte est le passage d'un pointeur nul à travers une liste d'arguments de fonction non typée. Dans moderne En C, cela ne se produit que lorsque vous devez passer un pointeur nul à une fonction qui prend un nombre variable d'arguments. (En C traditionnel, cela se produit pour toute fonction non déclarée avec un prototype). execl
où le tout dernier argument doit être un pointeur nul explicitement converti en (char *)
:
execl("/bin/ls", "ls", "-l", (char *)0); // correct
execl("/bin/ls", "ls", "-l", (char *)NULL); // correct, but unnecessarily verbose
execl("/bin/ls", "ls", "-l", 0); // undefined behavior
execl("/bin/ls", "ls", "-l", NULL); // ALSO undefined behavior
Oui, ce dernier exemple a un comportement non défini. même si NULL
est défini comme suit ((void *)0)
parce que void *
y char *
son no implicitement interconvertibles lorsqu'ils sont passés par une liste d'arguments non typée, même s'ils le sont partout ailleurs. (Il existe un langage dans C2011 qui les rend implicitement interconvertibles lorsqu'ils sont passés par une liste d'arguments non typée. va_arg
mais ils ont oublié de spécifier que les fonctions de bibliothèque fournies par l'implémentation accèdent aux arguments variadiques comme si elles appelaient va_arg
Vous ne pouvez donc vous y fier que pour les fonctions variadiques qui font partie de votre programme. Quelqu'un devrait probablement déposer un DR).
"Sous le capot", le problème ici est que no juste avec le modèle binaire utilisé pour un pointeur nul, mais que le compilateur peut avoir besoin de connaître le type concret exact de chaque argument afin de configurer correctement un cadre d'appel. (Considérez le MC68000, avec ses registres d'adresse et de données séparés ; certains ABIs spécifient que les arguments de pointeur doivent être passés dans les registres d'adresse mais les arguments entiers dans les registres de données. Considérez également toute ABI où int
y void *
ne sont pas de la même taille. Et c'est de plus en plus rare de nos jours, mais le C prévoit encore explicitement des possibilités de void *
y char *
n'ayant pas la même taille. (EDIT : je ne suis pas sûr, mais cela n'est peut-être plus autorisé). S'il existe un prototype de fonction, le compilateur peut l'utiliser, mais les fonctions non prototypées et les arguments variadiques n'offrent pas cette assistance.
Le C++ est plus compliqué et je ne me sens pas qualifié pour expliquer comment.
0 votes
bytes.com/topic/c/answers/213647-null-c
0 votes
Connexe stackoverflow.com/questions/459743/is-null-always-false
1 votes
c-faq.com/null/index.html
1 votes
Non, mais le zéro est toujours
NULL
.0 votes
@Philip : Seulement le zéro littéral, pas nécessairement les autres zéros.
0 votes
@DietrichEpp : quels autres zéros y a-t-il ?
5 votes
@Philip :
int x = 0; void *p = (void *) x;
Ici,x
a la valeur zéro, maisx
n'est pas le zéro littéral, doncp
n'est pas garanti comme étantNULL
et sur certaines plateformes bizarres, il ne le sera pas.NULL
. D'autre part,void *q = 0;
attribue toujoursNULL
aq
quelle que soit la plate-forme. Dans ce contexte, le terme "littéral" a une signification technique. Recherchez "integer literal".0 votes
Pour une réponse plus complète que celles affichées ci-dessous, consultez le site suivant Quelle est la différence entre les pointeurs nuls et NULL ? Pour répondre réellement à la question, une réponse doit séparer les termes pointeurs nuls, constantes de pointeur nul et la macro NULL.