68 votes

Comment vérifions-nous si un pointeur est un pointeur NULL?

Je pense toujours simplement que if(p != NULL){..} fera l'affaire. Mais après avoir lu cette question sur Stack Overflow, il semble que non.

Alors quelle est la manière canonique de vérifier les pointeurs NULL après avoir absorbé toute la discussion de cette question qui dit que les pointeurs NULL peuvent avoir une valeur non nulle?

4 votes

Ce n'est pas du c... c'est un fil c++... personnellement, je choisirais : if(p) {...}

4 votes

Vous vous inquiétez trop - votre code est bon, même en C++. Cette discussion était entre quelques juristes du langage - c'est un peu du genre "combien d'anges peuvent danser sur la tête d'une épingle".

0 votes

@forsvarir, quand if(p) sera-t-il différent de if(p != NULL)?

92voto

cnicutar Points 98451

Je pense toujours simplement que si (p != NULL){..} fera l'affaire.

Ça le fera.

0 votes

@cpuer Je connais peu le C++ mais d'après le livre que j'ai lu sur le C++ (C++ Primer Plus) je pense toujours que cela fonctionnera. Tant que NULL est défini comme quelque chose de non stupide.

4 votes

Ce style est considéré comme meilleur que if(p), car l'expression à l'intérieur d'une instruction if devrait être une expression booléenne, et "p" dans ce cas est un pointeur, pas un booléen. Il est considéré comme plus sûr et une meilleure pratique de vérifier explicitement contre zéro avec == ou != (MISRA-C: 2004 13.2).

4 votes

@Lundin : la condition à l'intérieur d'une instruction if doit seulement être convertible en un booléen; dans ce contexte p est équivalent à p != NULL, et c'est purement une question d'esthétique de choisir l'un ou l'autre. Aucun des deux n'est plus sûr ou pratique que l'autre.

41voto

James Kanze Points 96599

En premier lieu, pour être 100% clair, il n'y a aucune différence entre C et C++ ici. Et deuxièmement, la question Stack Overflow que vous citez ne parle pas des pointeurs nuls; elle introduit des pointeurs non valides; des pointeurs qui, du moins selon le standard, provoquent un comportement indéfini juste en essayant de les comparer. Il n'y a pas moyen de tester en général si un pointeur est valide.

En fin de compte, il existe trois façons courantes de vérifier un pointeur nul :

if ( p != NULL ) ...

if ( p != 0 ) ...

if ( p ) ...

Tous fonctionnent, peu importe la représentation d'un pointeur nul 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 nul du type de p, et les résultats de la conversion sont comparés à p. Peu importe la représentation d'un pointeur nul.

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

Lequel des deux premiers vous préférez est largement une question de style, peut-être partiellement dictée par votre style de programmation ailleurs : en fonction de 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 préféreraient NULL, mais dans quelque chose comme f( NULL ), le surcharge qui sera choisie est f( int ), et non une surcharge avec un pointeur. De même, si f est un modèle de fonction, f( NULL ) va instancier le modèle sur int. (Bien sûr, certains compilateurs, comme g++, généreront un avertissement si NULL est utilisé dans un contexte non-pointeur ; si vous utilisez g++, vous devriez vraiment 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 cela n'est pas compatible avec C:-).)

0 votes

@James Kanze, Je ne pense pas qu'il existe une conversion implicite comme void *p = main;if(p == 0x4004e3)printf("1\n"); imprime 1 (ici 0x4004e3 devrait être remplacé par l'adresse réelle de main). Cela dit, un pointeur peut être utilisé pour comparer avec un entier, et aucune conversion n'est impliquée.

0 votes

@compile-fan Bien sûr, il n'y a pas une telle conversion implicite. main a, en fait, un type très spécial; je ne pense pas qu'il y ait de moyen d'obtenir son adresse, du moins en C++, et si vous pouviez le faire, il n'y aurait rien que vous pourriez en faire. Mais en général, il n'y a pas de conversion implicite d'un type de pointeur à un autre, sauf pour le cas spécial où tout pointeur de données peut être converti en un void* avec des qualificateurs cv acceptables. Si le code que vous citez se compile, le compilateur est cassé.

0 votes

@James Kanze , cela compile en C, je pense que cela devrait également compiler en c++. Vous pouvez simplement mettre le code dans le corps de int main(int argc,char *argv[]){...}.

10voto

Simon Richter Points 11471

Le compilateur doit fournir un système de type cohérent et fournir un ensemble de conversions standard. Ni la valeur entière 0 ni le pointeur NULL n'ont besoin d'être représentés par des bits entièrement nuls, mais le compilateur doit se charger de convertir le token "0" du fichier d'entrée en la représentation correcte de zéro entier, et la conversion en type pointeur doit convertir de la représentation entière à la représentation pointeur.

L'implication de ceci est que

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

n'est pas garanti de se comporter de la même manière sur tous les systèmes cibles, car vous faites une hypothèse sur le motif binaire ici.

Par exemple, j'ai une plate-forme embarquée qui n'a pas de protection de mémoire et garde les vecteurs d'interruption à l'adresse 0, donc par convention, les entiers et les pointeurs sont XORés avec 0x2000000 lorsqu'ils sont convertis, ce qui laisse (void *)0 pointant vers une adresse qui génère une erreur de bus lorsqu'elle est déréférencée, cependant tester le pointeur avec une instruction if le renverra d'abord à une représentation entière, qui est alors entièrement nulle.

0 votes

D'accord, donc considérons le pointeur nul const (0, void *0, NULL) comme un cas spécial, que se passe-t-il lorsque l'on compare un pointeur avec un entier non nul? Merci de consulter ma question mise à jour ci-dessus :)

0 votes

Il vous reste à convertir l'une des valeurs pour qu'elles puissent être comparées, il n'existe pas d'opérateur de comparaison direct. Dans mon compilateur, cela signifie que soit le côté gauche soit le côté droit est XORé avant la comparaison, ce qui rend l'ensemble cohérent à nouveau.

0 votes

C'est sensé, mais ce n'est pas obligatoire. L'attribution de 0 à un int, puis la conversion explicite de cet int en pointeur est autorisée pour donner des résultats différents que la conversion implicite de la constante 0 en pointeur.

7voto

Mike Seymour Points 130519

La représentation réelle d'un pointeur nul est sans importance ici. Un littéral entier avec une valeur nulle (y compris 0 et toute définition valide de NULL) peut être converti en tout type de pointeur, donnant 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 des représentations non nulles du pointeur nul si vous écriviez quelque chose d'embrouillé comme p != reinterpret_cast(0), donc ne faites pas ça.

Je viens de remarquer que votre question est étiquetée C ainsi que C++. Ma réponse fait référence à C++, et d'autres langages peuvent être différents. Quel langage utilisez-vous?

0 votes

Que se passe-t-il lors de la comparaison d'un pointeur avec un entier non nul? Veuillez consulter ma question mise à jour ci-dessus :)

0 votes

@compile-fan: la comparaison avec un entier non nul ne devrait pas compiler, car un pointeur ne peut pas être comparé directement à un entier, et seul un littéral entier de valeur zéro peut être implicitement converti en pointeur (nul). Vous pouvez le forcer à compiler avec un cast douteux, mais alors le comportement est indéfini. (Encore une fois, je réponds pour le C++, mais je suis assez sûr que la réponse est la même en C).

6voto

pmg Points 52636

Apparemment, le fil de discussion auquel vous faites référence concerne le C++.

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

0 votes

@pmg, J'ai ajouté la balise c++, donc mon but est de trouver un moyen de vérifier les pointeurs nuls qui fonctionnera à la fois pour le C et le C++.

1 votes

@cpuer Continuez ce que vous faites! Vraiment, il n'y a pas de problème ici!

0 votes

Vérifier les pointeurs nuls n'est rien comparé aux problèmes auxquels vous serez confronté avec des fichiers source multi-langues. Je vous suggère de vous en tenir à une seule langue par fichier source. ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X