Dans une récente révision de code, un contributeur tente de faire en sorte que toutes les NULL
vérifications sur les pointeurs soient effectuées de la manière suivante:
int * some_ptr;
// ...
if (some_ptr == NULL)
{
// Handle null-pointer error
}
else
{
// Proceed
}
au lieu de
int * some_ptr;
// ...
if (some_ptr)
{
// Proceed
}
else
{
// Handle null-pointer error
}
Je conviens que son chemin est un peu plus clair dans le sens où il dit explicitement "Assurez-vous que ce pointeur n'est pas NULL", mais je le contredirais en disant que quiconque travaille sur ce code comprendrait que l'utilisation d'une variable de pointeur dans un if
instruction vérifie implicitement NULL
. De plus, je pense que la deuxième méthode a moins de chances d'introduire un bogue de ce genre:
if (some_ptr = NULL)
ce qui est juste une douleur absolue à trouver et à déboguer.
Quelle voie préférez-vous et pourquoi?
c++
c
if-statement
null
coding-style
Marbre Bryan
la source
la source
Réponses:
D'après mon expérience, les tests de la forme
if (ptr)
ouif (!ptr)
sont préférés. Ils ne dépendent pas de la définition du symboleNULL
. Ils n'exposent pas la possibilité d'une affectation accidentelle. Et ils sont clairs et succincts.Edit: Comme le souligne SoapBox dans un commentaire, ils sont compatibles avec les classes C ++ telles que
auto_ptr
qui sont des objets qui agissent comme des pointeurs et qui fournissent une conversionbool
pour activer exactement cet idiome. Pour ces objets, une comparaison explicite àNULL
devrait invoquer une conversion en pointeur qui peut avoir d'autres effets secondaires sémantiques ou être plus coûteuse que la simple vérification d'existence qu'implique labool
conversion.J'ai une préférence pour le code qui dit ce que cela signifie sans texte inutile.
if (ptr != NULL)
a la même signification queif (ptr)
mais au prix d'une spécificité redondante. La prochaine chose logique est d'écrireif ((ptr != NULL) == TRUE)
et c'est ainsi que réside la folie. Le langage C est clair qu'un booléen testé parif
,while
ou similaire a une signification spécifique de valeur non nulle est vrai et zéro est faux. La redondance ne le rend pas plus clair.la source
int y = *x; if (!x) {...}
où l'optimiseur est autorisé à raisonner que puisque*x
ne serait pas défini six
est NULL, il ne doit pas être NULL et!x
doit donc être FALSE. L'expression!ptr
n'est pas un comportement indéfini. Dans l'exemple, si le test a été effectué avant toute utilisation de*x
, alors l'optimiseur aurait tort d'éliminer le test.if (foo)
est assez clair. Utilise le.la source
Je vais commencer par ceci: la cohérence est roi, la décision est moins importante que la cohérence de votre base de code.
En C ++
NULL est défini comme 0 ou 0L en C ++.
Si vous avez lu le langage de programmation C ++ Bjarne Stroustrup suggère d'utiliser
0
explicitement pour éviter laNULL
macro lors de l'affectation , je ne sais pas s'il a fait la même chose avec les comparaisons, cela fait un moment que j'ai lu le livre, je pense qu'il vient de le faireif(some_ptr)
sans comparaison explicite mais je suis floue là-dessus.La raison en est que la
NULL
macro est trompeuse (comme presque toutes les macros le sont), elle est en fait0
littérale, pas un type unique comme son nom l'indique. Éviter les macros est l'une des directives générales en C ++. D'autre part,0
ressemble à un entier et ce n'est pas le cas lorsqu'il est comparé ou attribué à des pointeurs. Personnellement, je pourrais aller dans les deux sens, mais généralement, je saute la comparaison explicite (bien que certaines personnes n'aiment pas cela, c'est probablement pourquoi vous avez un contributeur suggérant de toute façon un changement).Indépendamment des sentiments personnels, c'est en grande partie un choix de moindre mal car il n'y a pas une seule bonne méthode.
C'est clair et un idiome courant et je le préfère, il n'y a aucune chance d'attribuer accidentellement une valeur lors de la comparaison et cela se lit clairement:
C'est clair si vous savez qu'il
some_ptr
s'agit d'un type de pointeur, mais cela peut aussi ressembler à une comparaison d'entiers:C'est clair, dans les cas courants, cela a du sens ... Mais c'est une abstraction qui fuit,
NULL
est en fait0
littérale et pourrait finir par être facilement utilisée à mauvais escient:C ++ 0x a nullptr qui est maintenant la méthode préférée car elle est explicite et précise, faites juste attention à l'affectation accidentelle:
Jusqu'à ce que vous soyez en mesure de migrer vers C ++ 0x, je dirais que c'est une perte de temps à vous soucier de laquelle de ces méthodes vous utilisez, elles sont toutes insuffisantes, c'est pourquoi nullptr a été inventé (avec des problèmes de programmation génériques qui ont abouti à une transmission parfaite .) Le plus important est de maintenir la cohérence.
En C
C est une bête différente.
En C NULL peut être défini comme 0 ou comme ((void *) 0), C99 autorise l'implémentation de constantes de pointeur nul définies. Cela revient donc à la définition de NULL par l'implémentation et vous devrez l'inspecter dans votre bibliothèque standard.
Les macros sont très courantes et en général, elles sont beaucoup utilisées pour compenser les lacunes du support de programmation générique dans le langage et d'autres choses. Le langage est beaucoup plus simple et le recours au pré-processeur est plus courant.
De ce point de vue, je recommanderais probablement d'utiliser la
NULL
définition de macro en C.la source
0
en C ++, il a un sens dans C:(void *)0
.0
est préférable àNULL
C ++, car les erreurs de type peuvent être un PITA.NULL
c'est zéro de toute façon.#define NULL ((void *)0)
delinux/stddef.h
NULL
doit être égal à zéro.J'utilise
if (ptr)
, mais cela ne vaut absolument pas la peine de discuter.J'aime mon chemin parce qu'il est concis, bien que d'autres disent
== NULL
qu'il est plus facile à lire et plus explicite. Je vois d'où ils viennent, je ne suis pas d'accord, les choses supplémentaires facilitent les choses. (Je déteste la macro, donc je suis partial.) À vous de décider.Je ne suis pas d'accord avec votre argument. Si vous ne recevez pas d'avertissements pour les affectations dans un conditionnel, vous devez augmenter vos niveaux d'avertissement. Aussi simple que cela. (Et pour l'amour de tout ce qui est bon, ne les changez pas.)
Note en C ++ 0x, nous pouvons le faire
if (ptr == nullptr)
, ce qui me fait plus agréable lecture. (Encore une fois, je déteste la macro. Maisnullptr
c'est bien.) Je le fais toujoursif (ptr)
, juste parce que c'est ce à quoi je suis habitué.la source
Franchement, je ne vois pas pourquoi c'est important. L'un ou l'autre est assez clair et toute personne moyennement expérimentée avec C ou C ++ devrait comprendre les deux. Un commentaire, cependant:
Si vous prévoyez de reconnaître l'erreur et de ne pas continuer à exécuter la fonction (c'est-à-dire que vous allez lancer une exception ou renvoyer un code d'erreur immédiatement), vous devez en faire une clause de garde:
De cette façon, vous évitez le "code fléché".
la source
if(!p)
est un comportement indéfini. Cela pourrait fonctionner ou non.if(!p)
n'est pas le comportement indéfini, c'est la ligne qui le précède. Etif(p==NULL)
aurait exactement le même problème.Personnellement, je l'ai toujours utilisé
if (ptr == NULL)
parce que cela rend mon intention explicite, mais à ce stade, c'est juste une habitude.L'utilisation
=
à la place de==
sera interceptée par tout compilateur compétent avec les paramètres d'avertissement corrects.Le point important est de choisir un style cohérent pour votre groupe et de s'y tenir. Quel que soit votre chemin, vous finirez par vous y habituer, et la perte de friction lorsque vous travaillez dans le code d'autres personnes sera la bienvenue.
la source
Encore un point en faveur de la
foo == NULL
pratique: sifoo
est, disons, unint *
ou unbool *
, alors leif (foo)
contrôle peut accidentellement être interprété par un lecteur comme testant la valeur de la pointee, c'est-à-dire commeif (*foo)
. LaNULL
comparaison ici est un rappel que nous parlons d'un pointeur.Mais je suppose qu'une bonne convention de dénomination rend cet argument sans objet.
la source
En fait, j'utilise les deux variantes.
Il y a des situations où vous vérifiez d'abord la validité d'un pointeur, et s'il est NULL, vous retournez / sortez simplement d'une fonction. (Je sais que cela peut conduire à la discussion "si une fonction n'a qu'un seul point de sortie")
La plupart du temps, vous vérifiez le pointeur, puis faites ce que vous voulez et résolvez le cas d'erreur. Le résultat peut être le vilain code indenté x fois avec plusieurs if.
la source
goto
peut être très pratique. De plus, dans de nombreux cas, unmalloc()
fichier nécessitant un nettoyage pourrait être remplacé par un fichier plus rapidealloca()
. Je sais qu'ils ne sont pas recommandés, mais ils existent pour une raison (pour moi, une étiquette bien nomméegoto
est beaucoup plus propre qu'unif/else
arbre obscurci ).alloca
est non standard et complètement non sûr. En cas d'échec, votre programme explose. Il n'y a aucune chance de récupération, et comme la pile est relativement petite, une panne est probable. En cas d'échec, il est possible que vous écrasiez le tas et introduisiez des vulnérabilités compromettant les privilèges. N'utilisez jamaisalloca
ou vlas à moins que vous n'ayez une petite limite sur la taille qui sera allouée (et alors vous pourriez aussi bien utiliser un tableau normal).Le langage de programmation C (K&R) vous demande de vérifier la valeur null == ptr pour éviter une affectation accidentelle.
la source
if (!valid)
ci-dessusif (valid == 0
).Si le style et le format font partie de vos critiques, il devrait y avoir un guide de style convenu pour mesurer. S'il y en a un, faites ce que dit le guide de style. S'il n'y en a pas, les détails comme celui-ci doivent être conservés tels qu'ils sont écrits. C'est une perte de temps et d'énergie, et distrait de ce que les révisions de code devraient vraiment révéler. Sérieusement, sans un guide de style, je pousserais pour ne PAS changer de code comme celui-ci par principe, même s'il n'utilise pas la convention que je préfère.
Et non pas que cela compte, mais ma préférence personnelle l'est
if (ptr)
. Le sens m'est plus immédiatement évident que mêmeif (ptr == NULL)
.Peut-être essaie-t-il de dire qu'il vaut mieux gérer les conditions d'erreur avant le chemin heureux? Dans ce cas, je ne suis toujours pas d'accord avec le critique. Je ne sais pas s'il existe une convention acceptée pour cela, mais à mon avis, la condition la plus «normale» devrait être la première dans toute déclaration if. De cette façon, j'ai moins de recherches à faire pour comprendre en quoi consiste la fonction et comment elle fonctionne.
L'exception à cela est si l'erreur me fait renoncer à la fonction ou si je peux m'en remettre avant de passer à autre chose. Dans ces cas, je gère l'erreur en premier:
En traitant la condition inhabituelle dès le départ, je peux m'en occuper et ensuite l'oublier. Mais si je ne peux pas revenir sur le chemin heureux en le traitant d'avance, alors il devrait être traité après le cas principal car cela rend le code plus compréhensible. À mon avis.
Mais si ce n'est pas dans un guide de style, c'est juste mon avis, et votre opinion est tout aussi valable. Soit normaliser, soit ne pas le faire. Ne laissez pas un critique pseudo-standardiser simplement parce qu'il a une opinion.
la source
C'est l'un des principes fondamentaux des deux langages que les pointeurs évaluent sur un type et une valeur qui peuvent être utilisés comme expression de contrôle,
bool
en C ++ etint
en C. Il suffit de l'utiliser.la source
if (foo = bar)
par accident.Par conséquent je préfère
ou
Cependant, si j'écrivais un ensemble de règles de style, je ne mettrais pas des choses comme ça dedans, je mettrais des choses comme:
la source
Je suis un grand fan du fait que C / C ++ ne vérifie pas les types dans les conditions booléennes dans
if
,for
et deswhile
déclarations. J'utilise toujours ce qui suit:même sur les entiers ou tout autre type qui se convertit en booléen:
Le codage dans ce style est plus lisible et plus clair pour moi. Juste mon avis personnel.
Récemment, en travaillant sur le microcontrôleur OKI 431, j'ai remarqué que ce qui suit:
est plus efficace que
car plus tard, le compilateur doit comparer la valeur de chx à 1. Où chx est juste un drapeau vrai / faux.
la source
La plupart des compilateurs que j'ai utilisés vont au moins avertir de l'
if
affectation sans autre sucre de syntaxe, donc je n'achète pas cet argument. Cela dit, j'ai utilisé les deux professionnellement et je n'ai aucune préférence pour l'un ou l'autre. Le== NULL
est certainement plus clair à mon avis.la source