web-dev-qa-db-fra.com

Comment vérifier si un pointeur est un pointeur NULL?

Je pense toujours que simplement if(p != NULL){..} fera le travail. Mais après avoir lu cette question de débordement de pile , il semble que non.

Alors quel est le moyen canonique de vérifier la présence de pointeurs NULL après en absorbant toute la discussion de cette question selon laquelle les pointeurs NULL peuvent avoir une valeur non nulle?

41
cpuer

Je pense toujours simplement si (p! = NULL) {..} fera le travail.

Ce sera.

52
cnicutar

Tout d'abord, pour être clair à 100%, il n'y a pas de différence entre C et C++ ici. Et deuxièmement, la question du débordement de pile que vous citez ne parle pas de pointeurs nuls; il introduit des pointeurs non valides; des indicateurs qui, du moins en ce qui concerne la norme, provoquent un comportement indéfini simplement en essayant de les comparer. Il n'y a aucun moyen de vérifier en général si un pointeur est valide.

En fin de compte, il existe trois méthodes répandues pour rechercher un pointeur nul:

if ( p != NULL ) ...

if ( p != 0 ) ...

if ( p ) ...

Tout fonctionne, indépendamment de la représentation d'un pointeur null sur la machine. Et tous, d'une manière ou d'une autre, sont trompeurs; lequel vous choisissez est une question de choisir le moins mauvais. Formellement, les deux premiers sont identiques pour le compilateur; la constante NULL ou 0 est convertie en un pointeur NULL du type p et les résultats de la conversion sont comparés à p. Indépendamment de la représentation d'un pointeur nul.

La troisième est légèrement différente: p est implicitement converti en bool. Mais la conversion implicite est définie comme les résultats de p != 0, Vous vous retrouvez donc avec la même chose. (Ce qui signifie qu'il n'y a vraiment aucun argument valable pour utiliser le troisième style: il obscurcit avec une conversion implicite, sans aucun avantage compensateur.)

Lequel des deux premiers choix est en grande partie une question de style, peut-être partiellement dicté par votre style de programmation ailleurs: selon l'idiome en question, l'un des mensonges sera plus gênant que l'autre. S'il ne s'agissait que d'une question de comparaison, je pense que la plupart des gens seraient en faveur de NULL, mais dans quelque chose comme f( NULL ), la surcharge qui sera choisie est f( int ), et pas une surcharge avec un pointeur. De même, si f est un modèle de fonction, f( NULL ) instanciera le modèle sur int. (Bien entendu, certains compilateurs, comme g ++, généreront un avertissement si NULL est utilisé dans un contexte sans pointeur; si vous utilisez g ++, vous devriez utiliser NULL.)

Dans C++ 11 , bien sûr, l'idiome préféré est:

if ( p != nullptr ) ...

, ce qui évite la plupart des problèmes avec les autres solutions. (Mais ce n'est pas compatible C :-).)

29
James Kanze

Le compilateur doit fournir un système de types cohérent et un ensemble de conversions standard. Ni la valeur entière 0 ni le pointeur NULL ne doivent être représentés par des bits nuls, mais le compilateur doit prendre soin de convertir le jeton "0" dans le fichier d'entrée en une représentation correcte pour l'entier zéro et la conversion en type de pointeur doit convertir un entier en représentation de pointeur.

L'implication de ceci est que

void *p;
memset(&p, 0, sizeof p);
if(p) { ... }

il n’est pas garanti que tous les systèmes cibles se comportent de la même manière, car vous faites ici une hypothèse sur le modèle de bits.

Par exemple, ma plate-forme intégrée ne dispose pas de protection de la mémoire et conserve les vecteurs d’interruption à l’adresse 0; ainsi, par convention, les entiers et les pointeurs sont XORés avec 0x2000000 lorsqu’ils sont convertis, ce qui laisse (void *) 0 pointant sur une adresse génère une erreur de bus lors de la déréférence, cependant le test du pointeur avec une instruction if le renverra d’abord en représentation entière, qui sera alors composée uniquement de zéros.

9
Simon Richter

La représentation réelle d'un pointeur nul est sans importance ici. Un littéral entier de valeur zéro (y compris 0 Et toute définition valide de NULL) peut être converti en tout type de pointeur, ce qui donne un pointeur nul, quelle que soit la représentation réelle. Donc p != NULL, p != 0 Et p sont tous des tests valides pour un pointeur non nul.

Vous pourriez rencontrer des problèmes avec les représentations non nulles du pointeur null si vous écrivez quelque chose de tordu comme p != reinterpret_cast<void*>(0), alors ne le faites pas.

Bien que je viens de remarquer que votre question porte les balises C et C++. Ma réponse fait référence à C++, et d'autres langages peuvent être différents. Quelle langue utilisez-vous?

6
Mike Seymour

Apparemment, le fil que vous mentionnez concerne environ C++.

Dans C votre extrait fonctionnera toujours. J'aime le plus simple if (p) { /* ... */ }.

4
pmg

La représentation des pointeurs n'a pas d'importance pour les comparer, car toutes les comparaisons en C ont lieu comme valeurs pas de représentations. La seule façon de comparer la représentation serait quelque chose de hideux comme:

static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
2
R..

Eh bien, cette question a été posée et répondue en 2011, mais il y a nullptrin C++ 11 . C'est tout ce que j'utilise actuellement.

Vous pouvez lire plus de Stack Overflow et aussi de cet article .

1
JohnJohn