En C, NULL
est défini comme (void *)0
alors qu'en C ++, il est 0
. Pourquoi est-ce? Dans CI, on peut comprendre que si NULL
n'est pas transtypé en typage à (void *)
compilateurs peuvent / ne peuvent pas générer d'avertissement. Autre que cela, y a-t-il une raison?
Réponses
Trop de publicités?En C++, le pointeur null est défini par la spécification ISO (§4.10/1)
Un pointeur null constante est une partie intégrante expression constante (5.19) rvalue de type entier qui prend la valeur de zéro.
C'est pourquoi, en C++, vous pouvez écrire
int* ptr = 0;
En C, cette règle est similaire, mais c'est un peu différent (§6.3.2.3/3):
Une constante entière expression avec la valeur 0, ou une expression en fonte de type
void *
, est appelé un pointeur null constante.55) Si un pointeur null constante est converti en type pointeur le pointeur résultant, appelé un pointeur null, c'est la garantie de comparer l'inégalité pour un pointeur sur un objet ou une fonction.
Par conséquent, les deux
int* ptr = 0;
et
int* ptr = (void *)0
sont juridique. Cependant, je suppose que l' void*
casting est ici de sorte que les déclarations comme
int x = NULL;
produire un avertissement du compilateur sur la plupart des systèmes. En C++, ce ne serait pas légal, car vous ne pouvez pas convertir implicitement un void*
à un autre type de pointeur implicitement, sans plâtre. Par exemple, ce qui est illégal:
int* ptr = (void*)0; // Legal C, illegal C++
Cependant, cela conduit à des problèmes, car le code
int x = NULL;
est juridique C++. De ce fait, et la confusion qui s'ensuivit (et l'autre cas, montré plus tard), C++11 a maintenant un mot-clé nullptr
représentant un pointeur null:
int* ptr = nullptr;
Cela n'a aucun des problèmes ci-dessus.
L'autre avantage de l' nullptr
- dessus de 0, c'est qu'il joue mieux avec le C++ type de système. Par exemple, supposons que j'ai ces deux fonctions:
void DoSomething(int x);
void DoSomething(char* x);
Si je l'appelle
DoSomething(NULL);
C'est l'équivalent de
DoSomething(0);
qui demande DoSomething(int)
à la place de l' DoSomething(char*)
. Cependant, avec nullptr
, je pourrais écrire
DoSomething(nullptr);
Et il appelle l' DoSomething(char*)
fonctionner comme prévu.
De même, supposons que j'ai un vector<Object*>
et que vous voulez définir chaque élément d'être un pointeur null. À l'aide de l' std::fill
algorithme, je pourrais essayer d'écrire
std::fill(v.begin(), v.end(), NULL);
Cependant, cela ne veut pas compiler, parce que le système de template de friandises NULL
comme int
et non pas un pointeur. Pour résoudre ce problème, j'aurais à écrire
std::fill(v.begin(), v.end(), (Object*)NULL);
C'est moche et un peu de défaites le but du système de template. Pour résoudre ce problème, je peux utiliser nullptr
:
std::fill(v.begin(), v.end(), nullptr);
Et depuis nullptr
est connu pour avoir un type correspondant à un pointeur null (plus précisément, std::nullptr_t
), cela permettra de compiler correctement.
Espérons que cette aide!
En C, NULL
augmente à un définis par l'implémentation de pointeur null constante". Un pointeur null constante est un entier expression constante avec la valeur 0, ou une expression en fonte d' void*
. Donc, C la mise en œuvre peut définir NULL
comme 0
ou ((void*)0)
.
En C++, les règles de pointeur null constantes sont différentes. En particulier, ((void*)0)
n'est pas une C++ pointeur null constante, donc une implémentation C++ ne peut pas définir NULL
de cette façon.
La raison pour laquelle C ++ utilise seulement 0
au lieu de (void*)0
est que vous pouvez définir un pointeur sur la fonction membre (MFP) sur NULL. Les types de MFP sont très stricts en termes de typage et ne peuvent pas être convertis (implicitement ou explicitement) en un type autre que les autres MFP de la même classe. Étant donné que (void*)
n'est pas un type de MFP, l'attribution de (void*)0
à un MFP n'est pas autorisée.
Toute utilisation autre que celle utilisée avec les MFP semblerait autoriser parfaitement (void*)0
.
Le langage C a été créé pour faciliter le programme de microprocesseurs. Un C pointeur est utilisé pour stocker l'adresse de données dans la mémoire. Une voie a été nécessaire pour représenter qu'un pointeur n'avait aucune valeur valide. L'adresse zéro a été choisi car tous les microprocesseurs utilisés à cette adresse pour le démarrage. Puisqu'il ne pouvait pas être utilisé pour autre chose que zéro était un bon choix pour représenter un pointeur avec aucune valeur valide. C++ est compatible avec le C il est donc hérité de cette convention.
L'exigence de la coulée de zéro lorsqu'il est utilisé comme un pointeur n'est qu'un ajout récent. Plus tard, des générations de C voulu avoir plus de rigueur (et espérons-le, moins d'erreurs), de sorte qu'ils ont commencé à être plus pointilleux sur la syntaxe.