Pourquoi est l'adresse zéro utilisé pour le pointeur null?
En C (ou C++ d'ailleurs), les pointeurs sont spéciales si elles ont la valeur zéro: je suis conseillé de définir des pointeurs vers zéro après la libération de leur mémoire, parce qu'il signifie de les libérer à nouveau le pointeur n'est pas dangereux, quand j'ai appeler malloc retourne un pointeur avec la valeur zéro si elle ne peut pas me faire de la mémoire; je l'utilise if (p != 0)
tout le temps à assurez-vous passé les pointeurs sont valides, etc.
Mais depuis adressage de mémoire commence à 0, n'est-ce pas 0 comme une adresse valide d'un autre? Comment peut-0 pour la manipulation de pointeurs null si c'est le cas? Pourquoi n'est-il pas un nombre négatif null à la place?
Edit:
Un tas de bonnes réponses. Je vais résumer ce qui a été dit dans les réponses exprimées comme mon propre esprit interprète et j'espère que la communauté va me corriger si j'ai mal compris.
-
Comme tout le reste dans la programmation, c'est une abstraction. Il suffit d'une constante, pas vraiment lié à l'adresse 0. C++0x souligne ce en ajoutant le mot-clé
nullptr
. -
Il n'est même pas une adresse de l'abstraction, c'est la constante spécifiée par la norme C et le compilateur peut se traduire par un autre nombre, tant qu'il permet de s'assurer à jamais, il équivaut à un "réel" de l'adresse, et est égal à d'autres pointeurs null si 0 n'est pas le meilleur de la valeur à utiliser pour la plate-forme.
-
Dans le cas où il n'est pas une abstraction, qui a été le cas dans les premiers jours, l'adresse 0 est utilisé par le système et hors des limites du programmeur.
-
Mon nombre négatif suggestion a été un peu sauvage de remue-méninges, je l'avoue. À l'aide d'un entier signé pour les adresses est un peu du gaspillage si cela signifie que, en dehors de pointeur null (-1 ou quoi que ce soit) la valeur de l'espace est divisé en parts égales entre les entiers positifs qui font des adresses valides et les nombres négatifs qui sont tout simplement perdu.
-
Si un nombre est toujours représentable par un type de données, c'est 0. (Probablement 1 l'est aussi. Je pense à celui-bit integer qui sera de 0 ou 1 si non signé, ou tout simplement l'signé bits si signé, ou les deux bits entier qui serait [-2, 1]. Mais ensuite, vous pouvez simplement aller de 0 nul et 1 étant le seul accessible octet en mémoire.)
Il y a quand même quelque chose qui est en suspens dans mon esprit. La Pile Overflow question Pointeur à une adresse fixe me dit que même si la valeur 0 pour le pointeur null est une abstraction, d'autres valeurs de pointeur ne sont pas nécessairement. Ce qui m'amène à poster une autre Pile Overflow question, Pourrais-je veux accéder à l'adresse zéro?.
- Vous pouvez tout aussi facilement changer
if (p != 0)
àif (p)
qui est une commune de l'idiome en C et C++, bien que vous aurez à sortir de l'habitude, si vous prenez Java. - La suppression de deux fois la même chose signifie que votre code est faux. Je vous déconseille de réglage des pointeurs à null après de sorte que vous pouvez planter et de résoudre le problème, pas la supprimer. En tout cas, vous faites l'erreur de supposer une adresse est certain entier. Ce n'est pas nécessairement vrai, et 0 représente simplement un peu de vraie valeur du pointeur qui est spécifique à l'implémentation. Un "négatif adresse" n'a pas de sens, sur le plan conceptuel.
- Peut-être même une bonne idée de définir un pointeur vers une adresse qui va forcer un blocage, comme
0xDEADBEEF
. - La question qui ne mourra jamais!
- Ne suivez pas GMan conseils. La suppression Multiple peut indiquer un problème théorique, mais ne va jamais à cause d'un problème. Un déréférencement/suppression d'un pointeur non valide sur l'autre main est toujours une question, MAIS la! ne doit pas nécessairement entraîner une panne. Il existe de nombreux cas dans lesquels vous pouvez déréférencement d'un pointeur non valide et simplement les résultats en complet de la folie et peut-être un accident plus tard. La seule fois que vous pouvez réellement pari (et non par le standard) que vous aurez un accident est si vous accédez à l'extérieur de votre programme de l'espace, qui a la valeur null sera certainement. UB peut causer des heures supplémentaires debug temps.
- Le point est définie sur null -> masquer les erreurs de programmation, ne définissez pas la valeur null -> trouver les erreurs de programmation. Je ne sais pas vous, mais j'aimerais avoir mon code correct.
- Les adresses ne sont pas signés,une valeur négative pourrait représentent simplement une très haute valeur en mémoire, selon la façon dont les OS cartes de mémoire virtuelle.
- Depuis que cette question est dans la langue de terre, je vais souligner les adresses ne sont pas nécessairement des entiers non signés.
- Depuis la non-char* pointeurs sont pratiquement toujours alignés (souvent sur une limite de 8 octets ces jours-ci), il peut être bénéfique pour les remplir de désallouer la mémoire de déchets octets dont le bit de poids faible jeu. J'utilise 0x61 mais c'est arbitraire. (L'avantage? Il vous donne une erreur/de signal due à des non-alignés d'accès lorsque vous déréférencement d'elle.)
- vous n'allez pas faire votre code correct en invoquant nasale démons. La suppression des pointeurs deux fois n'est jamais un code incorrect. Il peut ou peut ne pas être un problème de conception, mais il n'est jamais une erreur.
- Roberts: Selon la norme C, free()ing un pointeur deux fois les résultats dans un comportement indéfini. Je ne sais pas vous, mais j'essaie d'éviter que dans mes programmes.
- oui, bien sûr j'ai oublié de préciser que c'est uniquement le cas lorsque le pointeur a été fixé à 0 depuis la libération d'un 0 ptr est un nop. Je n'ai pas de considérer qu'il est nécessaire étant donné que la position je suis, argumentant contre, c'est que de ne pas définir un pointeur à null, il fait en quelque sorte plus facile de trouver un code d'erreurs causées par la suppression d'un pointeur deux fois.
- Êtes-vous d'accord que la suppression d'un pointeur deux fois, c'est parfois une erreur de logique?
- Mon mentionnant des conseils pour définir le pointeur à null après la suppression causé tout un débat. Je n'ai pas vraiment a me reposer, et je certainement ne pas compter ni sur la pratique. Pour les intéressés, cette discussion a sa page ici: stackoverflow.com/questions/1931126/...
- gman est correct. Le point entier dans C est pour éviter la surcharge de la vérification des contraintes au moment de l'exécution, sinon vous seriez de codage dans un sane langage comme Java. Il n'y a que quelques rares cas où vous double gratuit quelque chose, surtout depuis qu'elle est NULLE, tout d'abord..
- êtes-vous sûr de dire d'accord avec gman->ne pas définir un pointeur à null après la suppression parce que vous voulez bloquer si vous avez accidentellement gratuit il de nouveau... Vos mots des sons autrement.
- définir "erreur de logique". Il peut parfois être un pointeur null se faire supprimé est parce qu'il se passe autre chose qui ne devrait pas l'être. Si l'expose lui-même comme un bug dans le programme, alors c'est une erreur. Si la seule chose qui va "mal" c'est pas un pointeur null est passé à free() ou supprimer alors je pense que vous avez besoin de revoir votre définition de "erreur". En outre, l'alternative que gman propose ne garantit rien. La suppression d'un pointeur invalide, UB, pas de "crash". Plus souvent que pas, il exposera lui-même dans fous les moyens.
- Roberts, je suis d'accord avec gman que vous ne devriez pas régler le pointeur de quoi que ce soit pour la marque de nullité, sauf si c'est votre "vivant" drapeau... c'est à dire: Si vous avez une structure avec 3 pointeurs, et un drapeau en disant: météo la structure est en vie, vous ne réglez que le drapeau et de laisser le pointeur en tant que-est après leur libération.
- Si vous passez un pointeur vers une fonction qui estime que le pointeur est encore vivante, et il n'est pas, alors que c'est une erreur de logique. Même quand ils ne sont pas la cause directe de la plante, de les éviter n'est pas sans mérite. Il a tendance à faire des modifications plus facile si le code fonctionne comme prévu, plutôt que comme promis. Je ne veux pas dire que vous ne devriez pas régler morts pointeurs à null, mais en disant double suppression n'est jamais une erreur est tout simplement faux.
- "adressage de mémoire commence à 0" [citation nécessaire]
- Un plus pinailleurs détail 😬 Un un bits entier signé est composée de deux valeurs: 0 et -1, représenté sous la forme de 0 et de 1 que la seule valeur du bit, respectivement 🙂
- Paramètre un pointeur à null après la libération il peut cacher double-libre d'erreurs de conception. Ne pas le mettre à null peut en cacher utilisé après libéré des erreurs. Ce dernier est un ordre de grandeur plus graves. Si un pointeur n'est plus valide, vous voulez toute tentative de déférence pour résultat bien défini comportement au lieu d'imprévisible de corruption de la mémoire. Ces bugs sont l'enfer de la piste vers le bas et peut-être un trou de sécurité.
Vous devez vous connecter pour publier un commentaire.
2 points:
seulement la valeur de la constante 0 dans le code source est le pointeur null - la mise en œuvre de compilateur peut utiliser quelle que soit la valeur qu'elle veut ou a besoin dans l'exécution de code. Certaines plates-formes ont une valeur de pointeur qui s 'invalide' que la mise en œuvre pourrait utiliser comme pointeur null. La FAQ C a une question, "Sérieusement, avez-vous des machines réelles vraiment utilisé différente de zéro pointeurs null, ou des représentations différentes pour les pointeurs de types différents?", qui souligne plusieurs plates-formes, qui ont utilisé cette propriété de 0 étant le pointeur null en C source tandis que représentée différemment lors de l'exécution. La norme C++ a une note qui précise que la conversion "intégrante expression constante avec une valeur de zéro donne toujours un pointeur null, mais la conversion d'autres expressions qui ont la valeur zéro n'a pas besoin de donner un pointeur null".
une valeur négative peut être tout aussi utilisable par la plate-forme comme une adresse - le C standard avait simplement choisi quelque chose à utiliser pour indiquer un pointeur null, et zéro a été choisi. Je suis honnêtement pas sûr si d'autres sentinelles valeurs ont été considérées.
Les seules exigences pour un pointeur null sont:
if (p) ...
, la condition est évaluée à false si et seulement sip
est un pointeur null? Dois-je vraiment le comparer avecnullptr
(ouNULL
)?bool
expression et une "valeur de pointeur null" convertit àfalse
, sinontrue
. La valeur de pointeur null est ce que le pointeur null constante convertit lorsqu'il est utilisé comme un type de pointeur.0
n'est pas un pointeur, ni pointeur null. C'est une constante entière avec le typeint
. Avec#define NULL 0
,NULL
est le null le pointeur constant, mais il n'est pas un pointeur dans le cas, mais uneint
. Avec#define NULL ((void*)0)
,NULL
est aussi le null le pointeur constant, et un pointeur dans le cas. En C,NULL
, convertis en un type pointeur, est un pointeur null.0
plus facilement qu'un-1
, et un petit entière non nulle constante (qui pourrait s'adapter dans un opérande immédiat sur la plupart des machines) n'aurait pas de sens. Aussi, test pour le zéro a un soutien spécial dans la plupart des Isa. par exemple, pour analyser un littéral entier, vous avez probablement ajouté le dernier chiffre au total avec une instruction set condition de l'UC-codes, aka drapeaux, sur les Processeurs qui utilisent un registre de statut du tout. (La plupart des autres que MIPS). Il y a toujours un indicateur de zéro que de définir si le dernier résultat était nul, de sorte que vous n'avez pas besoin d'un autre comparer instruction, justejz
oujnz
.Historiquement, l'adresse de l'espace commençant à 0 a toujours été ROM, utilisé pour certains systèmes d'exploitation ou le faible niveau d'interruption de traitement des routines, de nos jours, puisque tout est virtuel (y compris l'adresse de l'espace), le système d'exploitation permet de mapper tout d'allocation d'adresse, de sorte qu'il peut ne PAS allouer quelque chose à l'adresse 0.
IIRC, le "pointeur null" la valeur n'est pas garantie à zéro. Le compilateur traduit de 0 quelle que soit la valeur "null est approprié pour le système (ce qui dans la pratique est probablement toujours à zéro, mais pas nécessairement). La même traduction est appliquée chaque fois que vous comparez un pointeur contre zéro. Parce que vous ne pouvez comparer les pointeurs les uns contre les autres et contre ce spécial-la valeur 0, il isole le programmeur de savoir quoi que ce soit à propos de la représentation de la mémoire du système. Quant à savoir pourquoi ils ont choisi de 0 au lieu de 42 ou somesuch, je suppose que c'est parce que la plupart des programmeurs commencent à compter à partir de 0 🙂 (d'ailleurs, sur la plupart des systèmes, 0 est la première adresse de la mémoire et qu'ils voulaient qu'il soit pratique, car dans la pratique des traductions comme je parle rarement lieu; la langue juste pour eux).
int* p = 0
) pourrait créer un pointeur contenant la valeur0xdeadbeef
ou toute autre valeur qu'il préfère. 0 est un pointeur null, mais un pointeur null est pas nécessairement un pointeur vers l'adresse zéro. 🙂0
n'est pas un pointeur null - c'est unint
. Exemple:printf("%p\n", 0);
UB.0
, lorsqu'ils sont convertis en un type pointeur, est un pointeur null.Vous devez être l'incompréhension de la signification de la constante de zéro dans le pointeur de contexte.
Ni en C et en C++ les pointeurs peuvent "ont une valeur de zéro". Les pointeurs ne sont pas arithmétique des objets. Ils canot ont des valeurs numériques comme "zéro" ou "négatif" ou quoi que ce soit de cette nature. Donc votre affirmation à propos de "pointeurs ... ont la valeur zéro" n'a simplement aucun sens.
Dans le C & C++ les pointeurs peuvent avoir réservé de pointeur null valeur. La représentation réelle de pointeur null valeur n'a rien à voir avec une quelconque "zéros". Il peut être absolument n'importe quoi approprié pour une plate-forme donnée. Il est vrai que sur la plupart des plaforms de pointeur null valeur est représentée physiquement par une réelle zéro la valeur de l'adresse. Cependant, si sur certaines plate-forme de l'adresse 0 est en fait utilisé pour un certain but (par exemple, vous pourriez avoir besoin pour créer des objets à l'adresse 0), le pointeur null valeur sur cette plate-forme sera probablement différent. Il pourrait être physiquement représenté par
0xFFFFFFFF
la valeur de l'adresse ou de0xBAADBAAD
la valeur de l'adresse, par exemple.Néanmoins, indépendamment de la façon dont le pointeur null valeur est representee sur une plate-forme donnée, dans votre code, vous pourrez toujours continuer à désigner null-pointeurs en constante
0
. Pour affecter un pointeur null valeur à un pointeur, vous pourrez continuer à utiliser des expressions commep = 0
. C'est le compilateur a la responsabilité de réaliser ce que vous voulez et de les traduire dans le bon de pointeur null la valeur de la représentation, c'est à dire à la traduire dans le code qui permettra de mettre la valeur de l'adresse de0xFFFFFFFF
dans le pointeurp
, par exemple.En bref, le fait que vous utilisez
0
dans votre sorce code pour générer de pointeur null valeurs ne signifie pas que le pointeur null valeur est en quelque sorte lié à l'adresse0
. Le0
que vous utilisez dans votre code source est juste "sucre syntaxique" qui n'a absolument aucun rapport avec la réalité physique de l'adresse de pointeur null valeur est "pointant" à.(p1 - nullptr) - (p2 - nullptr) == (p1 - p2)
.NULL
explicitement n'a pas besoin d'être représenté par un 0.Sur certains/beaucoup/tous les systèmes d'exploitation, la mémoire, l'adresse 0 est spécial d'une certaine façon. Par exemple, il est souvent mappés à des invalides/inexistant mémoire, ce qui provoque une exception si vous essayez d'y accéder.
Je pense que les valeurs de pointeur sont généralement traités comme des nombres non signés: sinon pour exemple un pointeur 32 bits ne serait en mesure d'adresse 2 GO de mémoire, au lieu de 4 GO.
J'imagine que la magie de la valeur 0 a été pris pour définir un pointeur non valide, car il pourrait être testée avec moins d'instructions. Certains langages machine automatiquement le zéro et de signer des drapeaux selon les données lors du chargement des registres, de sorte que vous pourraient test pour un pointeur null avec une simple charge, et les instructions de branchement sans faire un distinct comparer instruction.
(La plupart des Isa seulement définir des indicateurs sur ALU instructions, pas de charges, si. Et en général, vous ne produisent pas des pointeurs par calcul, sauf dans le compilateur lors de l'analyse C source. Mais au moins, vous n'avez pas besoin de l'arbitraire d'un pointeur de largeur constante à comparer.)
Sur le Commodore Pet, Vic20, et C64 qui ont été les premières machines, j'ai travaillé sur, la RAM a commencé à l'emplacement 0, donc il était tout à fait valable à lire et à écrire à l'aide d'un pointeur null si vous avez vraiment voulu.
Je pense que c'est juste une convention. Il doit y avoir une valeur d'un pointeur invalide.
Vous venez de perdre un octet de l'adresse de l'espace, c'est rarement un problème.
Il n'y a pas négatif des pointeurs. Les pointeurs sont toujours pas signés. Aussi, si ils pouvaient être négatifs de votre convention signifie que vous perdez la moitié de l'espace d'adressage.
char *p = (char *)1; --p;
. Depuis comportements sur un pointeur null est pas défini par la norme, ce système peut avoirp
réellement à lire et écrire l'adresse 0, incrément de donner l'adresse de1
, etc.char x = ((char*)0);
à lire l'adresse zéro et de stocker cette valeur dans x. Ce code donnerait un Comportement Indéfini de toute mise en œuvre, qui n'a pas de définir son comportement, mais le fait qu'une norme dit que quelque chose est un Comportement Indéfini, en aucune façon, interdit implémentations d'offrir à leurs propres spécifications pour ce qu'il va faire.*(char *)0
. C'est vrai, mais dans ma suggestion, la mise en œuvre n'a pas besoin de définir le comportement de*(char *)0
ou de tout autre pointeur null opérations.char *p = (char*)1; --p;
ne serait défini par la norme, si cette séquence a été réalisée après un pointeur vers quelque chose d'autre que le premier octet d'un objet avait été jeté à unintptr_t
, et le résultat de cette fonte qui s'est passé pour obtenir la valeur 1, et dans ce cas particulier, le résultat de--p
donnerait un pointeur vers l'octet précédent, celui dont la valeur du pointeur, lors de la fonte deintptr_t
, avaient donné1
.Bien que C utilise de 0 à représenter le pointeur null, gardez à l'esprit que la valeur du pointeur lui-même ne peut pas être un zéro. Cependant, la plupart des programmeurs ne jamais utiliser les systèmes où le pointeur null est, en fait, 0.
Mais pourquoi zéro? Eh bien, c'est une adresse que tous les systèmes d'actions. Et bien souvent, le faible adresses sont réservés pour le système d'exploitation fins ainsi la valeur fonctionne bien comme étant hors-limites pour les programmes d'application. Accidentelle d'affectation d'une valeur de nombre entier à un pointeur est susceptible de mettre fin à zéro comme rien d'autre.
Historiquement, la faible mémoire d'une application a été occupé par les ressources système. C'est dans ces jours que zéro est devenu la valeur null par défaut.
Alors que ce n'est pas nécessairement vrai pour les systèmes modernes, il est toujours une mauvaise idée de mettre les valeurs de pointeur à tout sauf à ce que l'allocation de mémoire a vous a remis.
Quant à l'argument de la non définition d'un pointeur à null après la suppression de sorte qu'à l'avenir les supprime "exposer les erreurs"...
Si vous êtes vraiment, vraiment inquiet à propos de ce alors une meilleure approche, qui est garanti pour fonctionner, est de tirer parti de la fonction assert():
Cela exige un peu de saisie, et un supplément de vérifier au cours de debug, mais il est certain à vous donner ce que vous voulez: avis quand ptr est supprimé 'double'. L'alternative donnée dans le commentaire la discussion, ne pas fixer le pointeur à null de sorte que vous aurez un accident, est tout simplement de ne pas être couronnée de succès. Pire, contrairement à ce qui précède, il peut provoquer une panne (ou bien pire!) sur un utilisateur si l'un de ces "bugs" se fait grâce à l'étagère. Enfin, cette version vous permet de continuer à exécuter le programme pour voir ce qui se passe réellement.
Je me rends compte ce n'est pas la réponse à la question posée, mais j'étais inquiet que quelqu'un en lisant les commentaires, peut venir à la conclusion qu'il est considéré comme une "bonne pratique" pour ne PAS définir des pointeurs à 0 si il est possible qu'ils obtiennent envoyé à free() ou supprimer deux fois. Dans de rares cas, lorsque c'est possible, il n'est JAMAIS une bonne pratique d'utiliser un Comportement non défini comme un outil de débogage. Personne n'a jamais eu à chasser vers le bas d'un bug qui a finalement été causé par la suppression d'un pointeur non valide serait de proposer cette. Ces types d'erreurs, de prendre des heures à traquer et presque toujours l'effet du programme sur un de totalement inattendu qu'il est difficile, voire impossible, de remonter à l'origine du problème.
Une importante raison pour laquelle de nombreux systèmes d'exploitation utilisent tous les bits à zéro pour le pointeur null représentation, c'est que cela signifie
memset(struct_with_pointers, 0, sizeof struct_with_pointers)
et similaire sera mis tous les pointeurs à l'intérieur destruct_with_pointers
de pointeurs null. Ce n'est pas garanti par la norme, mais beaucoup, beaucoup de programmes de l'assumer.Dans l'une des anciennes DÉC machines (PDP-8, je crois), le runtime C la mémoire de protéger la première page de la mémoire, de sorte que toute tentative d'accès à la mémoire dans ce bloc serait la cause d'une exception soulevée.
Le choix de la sentinelle de la valeur est arbitraire, et c'est en fait traitée par la prochaine version de C++ (officieusement connu comme "C++0x", les plus susceptibles d'être connu dans l'avenir que la norme ISO C++ 2011), avec l'introduction de la clé
nullptr
pour représenter une valeur null évalués pointeur. En C++, la valeur 0 peut être utilisée comme initialisation d'expression pour toute POD et pour n'importe quel objet avec un constructeur par défaut, et il a un sens particulier de l'attribution de la sentinelle de la valeur dans le cas d'un pointeur d'initialisation. Quant à savoir pourquoi une valeur négative n'a pas été choisi, adresses sont habituellement de 0 à 2N-1 pour une certaine valeur de N. En d'autres termes, les adresses sont généralement traitées comme des valeurs non signées. Si la valeur maximale ont été utilisés comme sentinelles de la valeur, alors il faudrait varier d'un système à l'autre en fonction de la taille de la mémoire alors que 0 est toujours représentable adresse. Il est également utilisé pour des raisons historiques, comme la mémoire de l'adresse 0 est généralement inutilisable dans les programmes, et de nos jours la plupart des OSs ont des parties du noyau chargé dans le bas de page(s) de mémoire, et ces pages sont généralement protégés de telle façon que si touché (déréférencé) par un programme (sauf le noyau) sera la cause d'une anomalie.Il doit avoir une certaine valeur. Évidemment, vous ne voulez pas marcher sur les valeurs que l'utilisateur peut légitimement souhaitez utiliser. Je présume que, depuis la C runtime fournit le segment BSS pour initialisé à zéro des données, il fait un certain degré de sens à interpréter de zéro, comme une liste non-initialisé la valeur du pointeur.
Rarement d'un système d'exploitation vous permettent d'écrire à l'adresse 0. Il est commun de bâton OS spécifique des choses bas dans la mémoire; à savoir, Idt, les tables de pages, etc. (Les tables sont dans la mémoire RAM, et il est plus facile de coller au fond que d'essayer de déterminer où le haut de RAM.) Et pas d'OS dans son esprit droit vous permettra de modifier les tables système de bon gré mal gré.
Cela peut ne pas avoir été sur le K&R esprits quand ils ont fait le C, mais il (ainsi que le fait que 0==null est assez facile à retenir) fait 0 un choix populaire.
La valeur
0
est une valeur spéciale qui prend différentes significations dans des expressions spécifiques. Dans le cas des pointeurs, comme cela a été souligné à plusieurs reprises, il est utilisé probablement parce qu'à l'époque c'était le moyen le plus pratique de dire "insérer la valeur par défaut sentinelle valeur ici." Comme une expression constante, il n'a pas la même signification qu'au niveau du bit à zéro (c'est à dire, tous les bits à zéro) dans le cadre d'un pointeur d'expression. En C++, il existe plusieurs types qui n'ont pas de bit-à-bit zéro de la représentation deNULL
comme pointeur de membre, et un pointeur de fonction membre.Heureusement, C++0x a un nouveau mot clé "expression qui signifie un connu de pointeur non valide qui n'a pas de carte d'or au niveau du bit à zéro pour l'intégrale des expressions":
nullptr
. Bien qu'il existe quelques systèmes que vous pouvez cibler avec C++ qui permettent de déférence de l'adresse 0 sans barfing, de sorte que programmeur, méfiez-vous.Il y a déjà beaucoup de bonnes réponses dans ce fil, il y a probablement plusieurs raisons pour préférer la valeur
0
des pointeurs null, mais je vais en ajouter deux de plus:Cela dépend de la mise en œuvre des pointeurs en C/C++. Il n'y a pas de raison particulière pourquoi NULL est équivalent dans les affectations à un pointeur.
Il y a des raisons historiques à cela, mais il y a aussi des raisons d'optimisation pour elle.
Il est commun pour le système d'exploitation afin d'assurer un processus avec des pages de mémoire initialisé à 0. Si un programme veut interpréter la partie de la page de mémoire comme un pointeur, alors il est de 0, donc il est assez facile pour le programme afin de déterminer que le pointeur n'est pas initialisé. (ceci ne fonctionne pas si bien lorsqu'il est appliqué à initialisée flash pages)
Une autre raison est que le nombre de (nombre de processeurs, il est très très facile de tester une valeur d'équivalence de 0. Il est parfois un gratuit comparaison fait sans toutes les instructions supplémentaires nécessaires, et peuvent généralement être fait sans avoir à fournir une valeur de zéro dans un autre registre, ou comme un littéral dans le volet enseignement de comparer.
Pas cher des comparaisons pour la plupart des processeurs sont signés, à moins de 0, et égale à 0. (signé supérieur à 0 et n'est pas égal à 0 sont sous-entendus par ces deux)
Depuis 1 valeur de toutes les valeurs possibles doit être réservé à de mauvaises ou non initialisé, alors vous pourriez aussi bien le faire celui qui a le moins cher le test d'équivalence de la mauvaise valeur. Cela est également vrai pour le '\0' terminé de chaînes de caractères.
Si vous essayez d'utiliser plus ou moins de 0 pour cet effet, puis vous vous retrouvez à dégainer votre plage d'adresses dans la moitié.
La constante
0
est utilisé à la place deNULL
parce que le C a été réalisée par des hommes des cavernes des milliards d'années,NULL
,NIL
,ZIP
, ouNADDA
aurait fait beaucoup plus de sens que0
.En effet. Bien que beaucoup de systèmes d'exploitation interdire vous de la cartographie quelque chose à l'adresse de zéro, même dans un espace d'adresse virtuelle (les gens ont réalisé que C est une insécurité linguistique, et qui reflète déréférencement de pointeur null bugs sont très communes, a décidé de les "fixer" par dissallowing l'utilisateur code de la carte à la page 0; Ainsi, si vous appelez une fonction de rappel, mais le rappel pointeur est NULL, vous ne finissent par l'exécution d'un code arbitraire).
Parce que
0
en comparaison à un pointeur sera remplacé par un de mise en œuvre spécifiques valeur, qui est la valeur de retour de malloc sur un malloc échec.Ce serait encore plus de confusion.
int
n'était pas seulement la même taille qu'un pointeur--dans de nombreux contextes, uneint
et un pointeur peut être utilisé de façon interchangeable. Si une routine attend un pointeur et on est passé dans un entier 57, la routine serait d'utiliser l'adresse avec le même modèle de bits que le nombre de 57. Sur ces machines, le motif de bits pour représenter un pointeur null est 0, donc en passant un int 0 passer un pointeur null.(Veuillez Lire Ce Paragraphe Avant de Lire le Post. Je demande à toute personne intéressée par la lecture de ce post devrait essayer de le lire attentivement, et bien sûr ne pas downvote jusqu'à ce que vous le comprendre complètement, merci.)
Il est maintenant wiki de la communauté, en tant que tel, si quelqu'un n'est pas d'accord avec les concepts, veuillez la modifier, avec une explication claire et détaillée de ce qui est mal et pourquoi, et si possible merci de citer les sources ou fournir la preuve que l'on peut reproduire.
Réponse
Voici quelques autres raisons qui pourraient être les facteurs sous-jacents NULL==0
if(!my_ptr)
au lieu deif(my_ptr==NULL)
.Ici, je Voudrais Dire Un Mot Sur les Autres Réponses
Pas Parce Que Du Sucre Syntaxique
Dire que NULL est égal à zéro à cause du sucre syntaxique, n'a pas trop de sens, si oui, pourquoi ne pas utiliser l'index 0 du tableau de tenir sa longueur?
En fait C est le langage qui ressemble le plus à la mise en œuvre interne, est-il sensé de dire que C repris de zéro juste parce que du sucre syntaxique? Ils seraient plutôt de fournir un mot-clé null (comme de nombreuses autres langues) plutôt que de la cartographie de zéro à la valeur NULL!
En tant que tel alors qu'aujourd'hui c'est peut-sucre syntaxique, il est clair que l'intention originale du langage C les développeurs n'était pas de sucre syntaxique, comme je le montrerai plus loin.
1) La Spécification
Pourtant, s'il est vrai que le C les spécifications parler de la constante 0 comme pointeur null (section 6.3.2.3), et également définir la valeur NULL à la mise en œuvre définies (article 7.19 dans le C11 spécification, et 7.17 dans le C99 spécification), le fait demeure que, dans le livre "le Langage C", écrit par les inventeurs de C comme indiqué dans la section 5.4:
Comme on peut le voir (à part la mention "adresse zéro") au moins à l'origine, l'intention des auteurs de C étaient de l'adresse zéro, et non pas la constante de zéro, en outre, il ressort de cet extrait que la raison pour laquelle la spécification parle de la constante zéro est probablement de ne pas exclure une expression qui est évaluée à zéro, mais au lieu d'inclure la constante entière zéro pour être la seule constante entière autorisés pour une utilisation dans un pointeur de contexte sans casting.
2) Résumé
Tandis que la spécification ne dit pas explicitement qu'une adresse zéro peut être traitée différente de la constante de zéro, il n'est pas dit que non, et le fait lorsque vous traitez avec les de pointeur null constante il n'a pas la prétention d'être mise en œuvre définies comme il le fait par le NULL défini constante, au lieu de le réclamer à zéro, montre qu'il pourrait y avoir une différence entre la constante de zéro et l'adresse zéro.
(Si c'est cependant le cas, je me demande juste pourquoi NULL est définie par l'implémentation, puisque dans un tel cas, la valeur NULL peut être aussi la constante de zéro, comme le compilateur a tout de même de convertir tous les zéro constantes dans la mise en œuvre effective définie NULLE?)
Cependant, je ne vois pas ce en action réelle, et dans les plates-formes de l'adresse zéro et la constante de zéro sont traités de la même façon, et jetez le même message d'erreur.
En outre, le fait est qu'aujourd'hui les systèmes d'exploitation sont en fait la réservation de la totalité de la première page (plage de 0x0000 à 0xFFFF), juste pour empêcher l'accès à l'adresse zéro à cause de C est de pointeur NULL (voir http://en.wikipedia.org/wiki/Zero_page, ainsi que "Windows Via C/C++ par Jeffrey Richter et Christophe Nasarre (publié par Microsoft Press)").
Donc je voudrais demander de quelqu'un qui prétend réellement avoir vu en action, s'il vous plaît spécifier la plate-forme, et le compilateur, et le code exact, effectivement, il l'a fait, (même si en raison de la vague de la définition dans la spécification [comme je l'ai montré] quel que soit le compilateur et de la plate-forme est libre de faire ce qu'il veut).
Cependant apparemment, il semble que les auteurs de C n'a pas eu cela à l'esprit, et ils parlaient de "adresse zéro", et que "C garantit que ce n'est pas une adresse valide", ainsi que "la valeur NULL est juste un mnémonique", montrant clairement qu'il avait initialement l'intention n'était pas de "sucre syntaxique".
Non Pas Parce Que Le Système D'Exploitation
Réclame aussi que le système d'exploitation refuse l'accès à l'adresse zéro, pour quelques raisons:
1) Lorsque C a été écrit il n'y a pas de telles restrictions, comme on peut le voir sur cette wikipage http://en.wikipedia.org/wiki/Zero_page.
2) Le fait est que les compilateurs C n'a accédé à la mémoire de l'adresse zéro.
Cela semble être le fait de l'article par BellLabs (http://www.cs.bell-labs.com/who/dmr/primevalC.html)
(En fait, au jour d'aujourd'hui (comme je les références citées ci-dessus à partir de wikipedia et microsoft press), la raison de la restriction de l'accès à l'adresse zéro est à cause de C pointeurs NULS! Ainsi, à la fin il s'avère être dans l'autre sens!)
3) Rappelez-vous que C est aussi utilisé pour écrire des systèmes d'exploitation, et même les compilateurs C!
En fait C a été développé dans le but d'écrire le système d'exploitation UNIX avec elle, et comme tel, il semble y avoir aucune raison pourquoi ils devraient se limiter à partir de l'adresse zéro.
(Matériel) Explication Sur La Façon Dont Les Ordinateurs Sont (Physiquement) En Mesure D'Accéder À L'Adresse Zéro
Il y a un autre point que je veux expliquer ici, comment est-il possible d'adresse de référence zéro à tous?
Pensez-y une seconde, les adresses sont extraites par le processeur, puis envoyé comme les tensions sur le bus mémoire, qui est ensuite utilisé par le système de mémoire pour obtenir l'adresse réelle, et encore une adresse de zéro signifie l'absence de tension, alors, comment est le matériel physique de la mémoire système accédant à l'adresse zéro?
La réponse semble être que l'adresse zéro est la valeur par défaut, et dans d'autres mots de l'adresse zéro est toujours accessible par le système de mémoire lorsque le bus mémoire est complètement éteint, et, comme telle, toute demande de lire ou d'écrire sans spécifier une adresse réelle (ce qui est le cas avec l'adresse zéro) est automatiquement accès à l'adresse zéro.