1
votes

Pourquoi y a-t-il un NULL dans le langage C?

Pourquoi y a-t-il un NULL dans le langage C? Existe-t-il un contexte dans lequel le simple littéral 0 ne fonctionnerait pas exactement de la même manière?

c

9 commentaires

Étant donné que NULL est autorisé à être défini comme 0 , alors nécessairement chaque instance où NULL apparaît doit, en supposant ISO C, fonctionner de la même manière si < code> 0 étaient là. Principalement, c'est du sucre syntaxique.


Copie possible de stackoverflow.com/q/1296843/1126841 .


Mais NULL peut être défini comme ((void *) 0) en C (pas en C ++).


@KenWhite la question concerne C, pas C ++


il est plus lisible d'utiliser NULL sur un pointeur plutôt que d'utiliser 0. Quand vous voyez if (a == NULL) cela vous aide à savoir que a est (très probablement ) un pointeur. mais quand vous voyez if (a == 0) vous pensez d'abord à un nombre (même il peut aussi être un pointeur).


Je me suis parfois demandé si NULL a été inventé historiquement pour essayer de supporter des implémentations où le pointeur nul n'était pas représenté par tous les bits-zéro, de sorte que NULL puisse être défini au lieu de 0xffffffff ou autre. Ensuite, il n'y aurait pas besoin de la règle actuelle selon laquelle 0 doit s'évaluer comme un pointeur nul, même si ce n'est pas tous bits-zéro. Mais peut-être que les programmeurs ne pouvaient pas se débarrasser de l'habitude d'utiliser simplement 0 , car le pointeur nul était tous bits-zéro sur leur plate-forme préférée, et le langage devait adopter la règle actuelle, sinon casser tout ce code.


@EricPostpischil: Pardon, de quels commentaires parlez-vous? "Chaque NULL peut être remplacé par 0" est exactement ce que j'ai dit dans mon premier commentaire. Je n'ai jamais dit que chaque 0 pouvait être remplacé par NULL .


@EricPostpischil: Mon deuxième commentaire supposait qu'il y avait peut-être déjà eu une intention de migrer vers une version de la langue où 0 ne serait pas autorisé en tant que constante de pointeur nul, et NULL serait requis à la place, et il serait autorisé à s'étendre à autre chose que 0 ou (void *) 0 . Bien sûr, rien de tel ne s'est jamais produit.


@NateEldredge: Désolé, peu importe.


5 Réponses :


3
votes

En fait, vous pouvez utiliser un littéral 0 partout où vous utiliseriez NULL .

Section 6.3.2.3p3 du C standard stipule:

Une expression constante entière avec la valeur 0, ou une expression convertie en type void * , est appelée un pointeur nul constante. Si une constante pointeur nul est convertie en un type pointeur, le pointeur résultant, appelé pointeur nul , est garanti comparer inégale à un pointeur vers n'importe quel objet ou fonction.

Et la section 7.19p3 déclare:

Les macros sont:

NULL

qui se développe en une constante de pointeur nulle définie par l'implémentation

Ainsi, 0 est qualifié de constante de pointeur nul, tout comme (void *) 0 et NULL . L'utilisation de NULL est cependant préférée car elle rend plus évidente pour le lecteur qu'un pointeur nul est utilisé et non la valeur entière 0.


1 commentaires

L'utilisation de NULL n'est pas seulement «préférée», et cela ne répond pas vraiment à la question posée par l'OP: «Y a-t-il un contexte dans lequel le simple littéral 0 ne serait pas fonctionne exactement de la même manière? Ce contexte est l'endroit où une erreur telle que où x est un int * et le programmeur a accidentellement tapé * x = 0; au lieu de x = 0; . Dans ce cas, le compilateur ne peut pas diagnostiquer l'erreur, mais il le pourrait si NULL était utilisé (et défini comme ((void *) 0) ). La différence n'est donc pas seulement une question de préférence, mais a des conséquences fonctionnelles réelles.



1
votes

C'est pour les humains et non pour les compilateurs.

si je vois dans le code p = NULL; au lieu de p = 0; il m'est beaucoup plus facile de comprendre que p est un pointeur et non un entier.

Pour les compilateurs, cela n'a pas d'importance, pour les humains.

De la même manière que nous utilisons des définitions au lieu de valeurs ou d'expressions "brutes" ou de noms de variables lisibles par l'homme comme loopCounter au lieu de p755_x .


2 commentaires

Non, NULL est également bénéfique pour les compilateurs. Si, pour certains int * x , un programmeur veut écrire x = pointeur nul; mais tape * x = pointeur nul; , le compilateur les auteurs aimeraient donner au programmeur un message d'erreur ou d'avertissement. Si le «pointeur nul» est 0 , le compilateur ne peut pas savoir qu'une erreur a été commise. S'il est NULL '(et que l'implémentation le définit convenablement, tel que ((void *) 0) `, le compilateur peut reconnaître qu'une erreur a été commise.


L'avertissement @EricPostpischil est de toute façon pour les humains :). Le compilateur s'en fiche et n'affecte pas la génération de code. godbolt.org/z/7hnxd3 . Donc je c'est important pour les humains - pas pour les compilateurs



0
votes

Le littéral constant entier 0 a des significations différentes selon le contexte dans lequel il est utilisé. Dans tous les cas, il s'agit toujours d'une constante entière de valeur 0, elle est juste décrite de différentes manières. À savoir, les objectifs les plus courants du pointeur NULL sont:

  1. Pour initialiser une variable de pointeur lorsque cette variable de pointeur n'est pas une adresse mémoire valide a encore été attribuée.
  2. Pour rechercher un pointeur nul avant d'accéder à un pointeur variable. Ce faisant, nous pouvons effectuer la gestion des erreurs dans le pointeur code associé, par exemple déréférencer la variable de pointeur uniquement si ce n'est pas le cas NULL.
  3. Pour passer un pointeur nul vers un argument de fonction lorsque nous ne le voulons pas pour transmettre toute adresse mémoire valide. ( ref )

1 commentaires

Cela ne répond pas à la question.



1
votes

Pourquoi y a-t-il un NULL dans le langage C?

Pour aider à clarifier l'affectation implique un pointeur et non un entier.

Exemple: strtok (char * s1, const char * s2); dans les deux cas ci-dessous reçoivent un pointeur nul car le NULL et le 0 sont tous deux convertis en un char * . Le premier est généralement considéré comme une meilleure auto-documentation. Pour un problème de style, suivez la norme de codage de votre groupe.

foo("Hello", "World", (char*) NULL);
// or 
foo("Hello", "World", (char*) 0);

Existe-t-il un contexte dans lequel le simple 0 littéral ne fonctionnerait pas exactement de la même manière?

Oui - lorsque le type d'origine est important.

0 est un int
NULL est un void * , ou int , unsigned ou long ou long long , etc. C'est la mise en œuvre définie.

Considérons une fonction qui prend un nombre variable de pointeurs, avec un pointeur nul sentinelle pour indiquer le dernier.

foo("Hello", "World", NULL);  // might work if `NULL` is a pointer.
foo("Hello", "World", 0);

Comme les arguments comme 0 et NULL ne sont pas convertis lorsqu'ils sont passés à un ... (à part certaines promotions), la fonction foo () pourrait ne pas y accéder de la même manière. Le code portable utiliserait:

strtok(s, NULL);
strtok(s, 0;

Une différence peut également se produire lorsque NULL , 0 sont passés à _Generic


0 commentaires

0
votes

NULL est utilisé pour indiquer clairement qu'il s'agit d'un type de pointeur.

Idéalement, l'implémentation C définirait NULL comme ((void *) 0) ou quelque chose d'équivalent, et les programmeurs utiliseraient toujours NULL quand ils veulent une constante de pointeur nulle.

Si cela est fait, alors, lorsqu'un programmeur a, par exemple, un int * x et écrit accidentellement * x = NULL; , alors le compilateur peut reconnaître qu'une erreur a été commise, car le côté gauche de = a le type int , et le côté droit a le type void * , et c'est pas une bonne combinaison pour l'attribution.

En revanche, si le programmeur écrit accidentellement * x = 0; au lieu de x = 0; , alors le compilateur ne peut pas reconnaître cette erreur, car le côté gauche a tapez int , et le côté droit a le type int , et c'est une combinaison valide.

Ainsi, lorsque NULL est bien défini et utilisé, les erreurs sont détectées plus tôt.

En particulier, répondez à votre question "Y a-t-il un contexte dans lequel le simple littéral 0 ne fonctionnerait pas exactement de la même manière?":

  • Dans un code correct, NULl et 0 peuvent être utilisés de manière interchangeable comme constantes de pointeur nul.
  • 0 fonctionnera comme une constante entière (sans pointeur), mais NULL peut ne pas fonctionner, selon la façon dont l'implémentation C le définit.
  • Pour détecter les erreurs, NULL et 0 ne fonctionnent pas exactement de la même manière; l'utilisation de NULL avec une bonne définition permet de détecter certaines erreurs que l'utilisation de 0 ne permet pas.

Le standard C permet d'utiliser 0 pour des constantes de pointeur nulles pour des raisons historiques. Cependant, cela n'est pas avantageux, sauf pour permettre au code précédemment écrit de se compiler dans des compilateurs utilisant les normes C actuelles. Le nouveau code devrait éviter d'utiliser 0 comme constante de pointeur nul.


0 commentaires