Question

Dans les premiers jours de C ++, lorsqu'il était verrouillé au-dessus de C, vous ne pouviez pas utiliser NULL car il était défini comme (void*)0. Vous ne pouviez attribuer NULL à aucun pointeur autre que void*, ce qui le rendait plutôt inutile. À l'époque, il était accepté que vous utilisiez 0 (zéro) pour les pointeurs nuls.

Jusqu'à ce jour, j'ai continué à utiliser zéro comme pointeur nul, mais ceux qui m'entourent insistent pour utiliser NULL. Personnellement, je ne vois aucun avantage à donner un nom (p && !q) à une valeur existante - et depuis, j’aime également tester les pointeurs en tant que valeurs de vérité:

if (p && !q)
  do_something();

puis utiliser zéro a plus de sens (comme si vous utilisiez <=>, vous ne pouvez pas utiliser logiquement <=> - vous devez explicitement comparer avec <=>, sauf si vous supposez que <=> est égal à zéro, auquel cas pourquoi utilisez <=>).

Existe-t-il une raison objective de préférer zéro à NULL (ou vice versa), ou s'agit-il uniquement d'une préférence personnelle?

Éditer: Je devrais ajouter (et je voulais dire à l'origine) que, avec RAII et les exceptions, j'utilise rarement les pointeurs zéro / nul, mais que vous en avez parfois besoin.

Était-ce utile?

La solution

Voici ce que Stroustrup a à dire: FAQ sur les styles et techniques C ++

  

En C ++, la définition de NULL est 0. Il n'y a donc qu'une différence esthétique. Je préfère éviter les macros et j'utilise donc 0. Un autre problème avec nullptr est que les gens croient parfois à tort qu'il est différent de 0 et / ou n'est pas un entier. Dans le code pré-standard, <=> était / est parfois défini comme un élément inapproprié et doit donc / doit être évité. C'est moins courant ces jours-ci.

     

Si vous devez nommer le pointeur null, appelez-le <=>; c'est ce qu'on appelle en C ++ 11. Ensuite, <=> sera un mot clé.

Cela dit, ne vous laissez pas aller à la sueur.

Autres conseils

Il existe quelques arguments (dont l'un est relativement récent) qui, à mon avis, contredisent la position de Bjarne à ce sujet.

  1. Documentation de l'intention

L'utilisation de NULL permet d'effectuer des recherches sur son utilisation et indique également que le développeur souhaitait utiliser un pointeur int, qu'il soit interprété ou non par le compilateur comme 0 ou pas.

  1. La surcharge du pointeur et du "int" est relativement rare

L'exemple cité par tout le monde est:

void foo(int*);
void foo (int);

void bar() {
  foo (NULL);  // Calls 'foo(int)'
}

Cependant, à mon avis au moins, le problème avec ce qui précède n’est pas que nous utilisons NULL pour la constante du pointeur null, c’est que nous avons des surcharges de 'foo' qui prennent des types d’arguments très différents. Le paramètre doit également être un std::nullptr_t, car tout autre type entraînera un appel ambigu et générera donc un avertissement utile du compilateur.

  1. Les outils d'analyse peuvent aider AUJOURD'HUI!

Même en l'absence de C ++ 0x, il existe aujourd'hui des outils permettant de vérifier que <=> est utilisé pour les pointeurs et que <=> est utilisé pour les types intégraux.

  1. C ++ 11 aura un nouveau type <=>.

Ceci est le dernier argument de la table. Le problème de <=> et <=> est activement résolu pour C ++ 0x et vous pouvez garantir que, pour chaque implémentation fournissant <=>, la toute première chose à faire est:

#define NULL  nullptr

Pour ceux qui utilisent <=> plutôt que <=>, le changement sera une amélioration de la sécurité de type avec peu d'effort ou aucun effort - il peut même attraper quelques bugs pour lesquels ils ont utilisé <=> pour <=> Pour tous ceux qui utilisent <=> aujourd'hui ... euh ... eh bien, espérons qu'ils aient une bonne connaissance des expressions régulières ...

Utilisez NULL. NULL indique votre intention. Le fait qu’il s’agisse de 0 est un détail d’implémentation qui ne devrait pas importer.

J'ai arrêté d'utiliser NULL au profit de 0 depuis longtemps (ainsi que de nombreuses autres macros). Je l'ai fait non seulement pour éviter autant que possible les macros, mais également parce que NULL semble être devenu trop utilisé dans les codes C et C ++. Il semble être utilisé chaque fois qu'une valeur 0 est requise, pas seulement pour les pointeurs.

Sur les nouveaux projets, j'ai placé ceci dans un en-tête de projet:

static const int nullptr = 0;

Maintenant, lorsque les compilateurs conformes à C ++ 0x arrivent, tout ce que je dois faire est de supprimer cette ligne. Un avantage intéressant de cette fonctionnalité est que Visual Studio reconnaît déjà nullptr en tant que mot clé et le met en évidence de manière appropriée.

j'utilise toujours:

  • NULL pour les pointeurs
  • '\0' pour les caractères
  • 0.0 pour les flotteurs et les doubles

où 0 irait bien. C'est une question d'intention de signalisation. Cela dit, je ne suis pas au courant.

    cerr << sizeof(0) << endl;
    cerr << sizeof(NULL) << endl;
    cerr << sizeof(void*) << endl;

    ============
    On a 64-bit gcc RHEL platform you get:
    4
    8
    8
    ================

La morale de l'histoire. Vous devez utiliser NULL lorsque vous utilisez des pointeurs.

1) Il déclare votre intention (ne me faites pas chercher dans tout votre code pour essayer de déterminer si une variable est un pointeur ou un type numérique).

2) Dans certains appels d'API qui attendent des arguments variables, ils utiliseront un pointeur NULL pour indiquer la fin de la liste d'arguments. Dans ce cas, utiliser un '0' au lieu de NULL peut causer des problèmes. Sur une plate-forme 64 bits, l'appel va_arg demande un pointeur 64 bits, mais vous ne transmettez qu'un entier 32 bits. Il me semble que vous vous fiez aux autres 32 bits pour être mis à zéro pour vous? J'ai vu certains compilateurs (par exemple, l'icpc d'Intel) qui ne sont pas aussi élégants - et cela a entraîné des erreurs d'exécution.

Si je me souviens bien, NULL est défini différemment dans les en-têtes que j'ai utilisés. Pour C, il est défini comme (void *) 0, et pour C ++, il n'est défini que comme 0. Le code ressemblait à quelque chose comme:

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

Personnellement, j'utilise toujours la valeur NULL pour représenter les pointeurs nuls, cela indique clairement que vous utilisez un pointeur plutôt qu'un type intégral. Oui en interne, la valeur NULL est toujours 0 mais elle n'est pas représentée en tant que telle.

De plus, je ne compte pas sur la conversion automatique d'entiers en valeurs booléennes, mais les compare explicitement.

Par exemple, préférez utiliser:

if (pointer_value != NULL || integer_value == 0)

plutôt que:

if (pointer_value || !integer_value)

Il suffit de dire que tout cela est corrigé dans C ++ 11, où l'on peut simplement utiliser nullptr au lieu de NULL, et aussi nullptr_t qui est le type d'un <=>.

Je dirais que l'histoire a parlé et que ceux qui ont plaidé en faveur de l'utilisation de 0 (zéro) se sont trompés (y compris Bjarne Stroustrup). Les arguments en faveur de 0 étaient principalement l’esthétique et la & "Préférence personnelle &";

.

Après la création de C ++ 11, avec son nouveau type nullptr, certains compilateurs ont commencé à se plaindre (avec les paramètres par défaut) du passage de 0 à des fonctions avec des arguments de pointeur, car 0 n’est pas un pointeur.

Si le code avait été écrit en utilisant NULL, une recherche et un remplacement simples auraient pu être effectués via la base de code pour le rendre nullptr à la place. Si vous êtes coincé avec du code écrit en utilisant le choix de 0 comme pointeur, il est beaucoup plus fastidieux de le mettre à jour.

Et si vous devez écrire un nouveau code dès maintenant au standard C ++ 03 (et que vous ne pouvez pas utiliser nullptr), vous devez utiliser NULL. Cela vous facilitera grandement la mise à jour à l'avenir.

J'utilise habituellement 0. Je n'aime pas les macros et il n'y a aucune garantie qu'un en-tête tiers que vous utilisez ne redéfinit pas NULL pour qu'il soit étrange.

Vous pouvez utiliser un objet nullptr tel que proposé par Scott Meyers et d'autres jusqu'à ce que C ++ obtienne un mot clé nullptr:

const // It is a const object...
class nullptr_t 
{
public:
    template<class T>
    operator T*() const // convertible to any type of null non-member pointer...
    { return 0; }

    template<class C, class T>
    operator T C::*() const   // or any type of null member pointer...
    { return 0; }

private:
    void operator&() const;  // Can't take address of nullptr

} nullptr = {};

Google " nullptr " pour plus d'informations.

J'ai déjà travaillé sur une machine où 0 était une adresse valide et NULL était défini comme une valeur octale spéciale. Sur cette machine (0! = NULL), un code tel que

char *p;

...

if (p) { ... }

ne fonctionnerait pas comme prévu. Vous deviez écrire

if (p != NULL) { ... }

Bien que je pense que la plupart des compilateurs définissent NULL à 0, je me souviens encore de la leçon de ces années: NULL n'est pas nécessairement 0.

Je pense que la norme garantit que NULL == 0, vous pouvez donc faire l’un ou l’autre. Je préfère NULL parce que cela documente votre intention.

L'utilisation de 0 ou de NULL aura le même effet.

Cependant, cela ne veut pas dire que ce sont deux bonnes pratiques de programmation. Étant donné qu'il n'y a pas de différence de performance, choisir une option de bas niveau plutôt qu'une solution agnostique / abstraite est une mauvaise pratique de programmation. Aidez les lecteurs de votre code à comprendre votre processus de réflexion .

NULL, 0, 0.0, '\ 0', 0x00 et quoi encore se traduisent par la même chose, mais sont des entités logiques différentes dans votre programme. Ils devraient être utilisés comme tels. NULL est un pointeur, 0 est une quantité, 0x0 est une valeur dont les bits sont intéressants, etc. Vous n'affecteriez pas '\ 0' à un pointeur, qu'il compile ou non.

Je sais que certaines communautés encouragent la démonstration d'une connaissance approfondie d'un environnement en rompant les contrats de celui-ci. Les programmeurs responsables créent toutefois du code maintenable et préservent ces pratiques de leur code.

Étrange, personne, y compris Stroustroup, n’a mentionné cela. Lorsqu’on a beaucoup parlé de normes et d’esthétique, personne n’a remarqué qu’il est dangereux d’utiliser 0 à la place de NULL, par exemple, dans la liste des arguments variables de l’architecture où sizeof(int) != sizeof(void*). Comme Stroustroup, je préfère <=> pour des raisons esthétiques, mais il faut veiller à ne pas l'utiliser là où son type pourrait être ambigu.

J'essaie d'éviter toute la question en utilisant autant que possible les références C ++. Plutôt que

void foo(const Bar* pBar) { ... }

vous pourrez souvent écrire

void foo(const Bar& bar) { ... }

Bien sûr, cela ne fonctionne pas toujours; mais les pointeurs nuls peuvent être surutilisés.

Je suis avec Stroustrup sur celui-ci :-) Puisque NULL ne fait pas partie du langage, je préfère utiliser 0.

Préférence essentiellement personnelle, bien que l'on puisse argumenter que NULL indique clairement que l'objet est un pointeur qui ne pointe actuellement vers rien, par exemple.

void *ptr = &something;
/* lots o' code */
ptr = NULL; // more obvious that it's a pointer and not being used

IIRC, la norme n'exige pas que NULL soit égal à 0. Vous devez donc utiliser ce qui est défini dans < stddef.h > est probablement le meilleur pour votre compilateur.

Une autre facette de l’argument est de savoir si vous devez utiliser des comparaisons logiques (conversion implicite en bool) ou une vérification explicite contre NULL, mais cela se résume également à la lisibilité.

Je préfère utiliser NULL car il est clair que votre intention est que la valeur représente un pointeur et non une valeur arithmétique. Le fait que ce soit une macro est regrettable, mais comme elle est si largement enracinée, il y a peu de danger (à moins que quelqu'un ne fasse quelque chose de vraiment stupide). J'aimerais que ce soit un mot-clé depuis le début, mais que pouvez-vous faire?

Cela dit, je n'ai aucun problème à utiliser les pointeurs comme valeurs de vérité en eux-mêmes. Comme avec NULL, c’est un idiome enraciné.

C ++ 09 ajoutera la construction nullptr qui, je pense, est attendue depuis longtemps.

J'utilise toujours 0. Pas pour une raison vraiment réfléchie, simplement parce que lorsque j'ai appris le C ++, j'ai lu quelque chose qui recommandait d'utiliser 0 et que je viens toujours de faire de cette façon. En théorie, il pourrait y avoir un problème de lisibilité au niveau de la lisibilité, mais en pratique, je n'ai jamais rencontré un tel problème en milliers d'heures de travail et en millions de lignes de code. Comme le dit Stroustrup, il ne s’agit en réalité que d’une question d’esthétique personnelle jusqu’à ce que le standard devienne nullptr.

Quelqu'un m'a dit une fois ... Je vais redéfinir NULL à 69. Depuis, je ne l'utilise plus: P

Cela rend votre code assez vulnérable.

Modifier:

Tout n'est pas parfait dans la norme. La macro NULL est une constante de pointeur null C ++ définie par l’implémentation qui n’est pas entièrement compatible avec la macro C NULL. Outre le masque qui le masque implicitement, elle est convertie en un outil inutile et sujet aux erreurs.

NULL ne se comporte pas comme un pointeur null mais comme un littéral O / OL.

Dites-moi que l'exemple suivant ne prête pas à confusion:

void foo(char *); 
void foo(int); 
foo(NULL); // calls int version instead of pointer version! 

C’est à cause de tout cela que la nouvelle norme apparaît std :: nullptr_t

Si vous ne voulez pas attendre la nouvelle norme et souhaitez utiliser un nullptr, utilisez au moins un modèle décent comme celui proposé par Meyers (voir le commentaire jon.h).

Eh bien, je préconise de ne pas utiliser de pointeurs 0 ou NULL autant que possible.

Leur utilisation conduira tôt ou tard à des erreurs de segmentation dans votre code. D'après mon expérience, ceci et les pointeurs généraux sont l'une des plus grandes sources de bogues en C ++

également, cela conduit à & "if-not-null &"; déclarations partout dans votre code. Bien plus agréable si vous pouvez toujours compter sur un état valide.

Il y a presque toujours une meilleure alternative.

Définir un pointeur sur 0 n’est tout simplement pas si clair. Surtout si vous utilisez un langage autre que le C ++. Cela inclut C ainsi que Javascript.

J'ai récemment corrigé avec du code comme celui-ci:

virtual void DrawTo(BITMAP *buffer) =0;

pour la fonction virtuelle pure pour la première fois. Je pensais que ce serait un jiberjash magique pendant une semaine. Lorsque j’ai réalisé qu’il s’agissait simplement de définir le pointeur de fonction sur null (les fonctions virtuelles ne sont que des indicateurs de fonction dans la plupart des cas pour C ++), je me suis lancé.

virtual void DrawTo(BITMAP *buffer) =null;

aurait été moins déroutant que cette raclée sans un espacement approprié pour mes nouveaux yeux. En fait, je me demande pourquoi C ++ n'utilise pas les minuscules <=> tout comme il utilise les minuscules false et true maintenant.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top