Existe-t-il une raison pragmatique pour utiliser «si (0 == p)» au lieu de «si (! p)»?

Je suis enclin à écrire des instructions if en utilisant l’opérateur de négation logique:

if (!p) some_code(); 

Certaines personnes autour de moi ont tendance à utiliser une comparaison explicite, de sorte que le code ressemble à ceci:

 if (FOO == p) some_code(); 

où FOO est l’un de faux , FAUX , 0 , 0.0 , NULL , etc.

Je préfère la forme courte parce que c’est:

  • operator!= sympa
  • generic programming conviviale
  • laconique (et encore plus belle , quant à moi)

Quels sont les avantages pragmatiques d’écrire ceci autrement (le cas échéant)?

Certains prétendent que l’avantage pragmatique est que les programmeurs auront plus de facilité à comprendre si vous comparez explicitement à NULL, FALSE, 0, etc., alors que l’opérateur logique peut être déroutant pour les personnes qui ne comprennent pas comment les conversions implicites et les booléens fonctionnent. C / C ++.

(Avertissement: je ne partage pas ce sharepoint vue moi-même. if (p) ... et if (!p)... sont les moyens idiomatiques d’exprimer cela en C et C ++, et les programmeurs qui ont du mal à les comprendre n’ont rien à faire. touchant le code C ou C ++. Le commentaire de Heath Hunnicutt est mort.)

Pour contraster la réponse de @ Erik, je dirais: utilisez ! pour la lisibilité. Si vous constatez que vous la négligez, faites tester vos yeux. Et après? Éviter 1, utilisez 3 – 2 à la place?

Utilisez (0 == p) ou (p == 0) pour plus de lisibilité. Ça ! est plus facile à négliger au premier abord que == 0

Utilisez (0 == p) si vous avez l’habitude d’ignorer les avertissements du compilateur et si vous voulez savoir quand vous utilisez = plutôt que ==.

Cela dépend de ce que p représente.

Si p représente une valeur booléenne / logique, alors (!p) semble le plus approprié – la comparaison avec “FALSE” est généralement déconseillée. Je n’anticipe pas beaucoup de débat.

Si p représente une valeur, comme un compteur, alors (p == 0) ou (0 == p) semble approprié. (Il y a généralement un débat animé entre les deux. Je trouve le premier plus lisible, mais le second évite des problèmes très sérieux.) Hormis laquelle des deux options est la meilleure, je ne prévois pas qu’il s’agisse d’un débat (comme dans , il devrait comparer à 0.)

Si p représente un pointeur, vous avez quelques problèmes. Un programmeur C ++ compétent devrait savoir que (!p) vous dira s’il est nul ou non. Cependant, l’idée de la lisibilité de cette question est une zone grise et j’estime qu’il s’agit d’un débat très contesté.

Personnellement, je suis un peu fatigué de la conversion implicite de int en boolean. Je ne pense pas que cela ajoute beaucoup au langage C. Dans C89 où il n’y a pas de type booléen, il est parfaitement raisonnable d’utiliser un entier comme booléen, auquel cas la conversion conduit à un code de belle apparence. Je vois pourquoi on ne peut pas le supprimer, en particulier lorsqu’il s’agit de bibliothèques qui, pour des raisons de compatibilité, ne peuvent pas être modifiées pour renvoyer un booléen, il en existe déjà un. Mais je ne pense certainement pas que cela devrait être utilisé dans tous les cas.

Parfois, une valeur entière égale à 0 signifie “il n’y en a pas un”, mais parfois cela signifie “il y en a un et c’est zéro”. Donc je suis content de:

 users = get_number_of_users(); if (users) { // there are users ... } else { // there aren't users } 

Je ne suis pas du tout enthousiaste pour:

 length = strlen(ptr); if (length) { // there is length? OK, sort of... } else { // there isn't length? No, wait, there *is* a length, that length is 0 } 

Donc, il y a votre raison pragmatique d’écrire if (length == 0) de préférence à if (!length) . “If not length” n’a pas de sens en anglais , donc ce n’est pas nécessairement ce que vous devriez écrire dans le code non plus.

Certes, 0 été inventé comme un lieu spécial pour signifier “il n’y en a pas”. Mais la prise de conscience que dans de nombreux contextes, il pouvait être traité comme un nombre comme un autre était une avancée importante dans l’histoire des mathématiques, et je ne pense pas que nous devrions écarter cela simplement parce que C nous fournit une syntaxe pour le traiter à nouveau spécialement 😉 Si vous voulez savoir si un nombre est égal à 5, comparez-le à 5, et normalement je pense que la même chose devrait être valable pour 0.

Un avantage non encore mentionné de la version de if (!Foo) est qu’elle fonctionnera avec les classes qui utilisaient l’ idiome booléen sécurisé . Dans les classes qui implémentent cela, les opérateurs de comparaison des classes échoueront (par exemple, Foo==0 ne sera pas défini) mais !Foo appellera un opérateur de conversion sur Foo, renvoyant un pointeur sur une fonction membre (ou un pointeur nul, si Foo doit être traité comme faux). Un certain nombre de classes Boost, telles que shared_ptr, utilisent cette technique.

Je mettrais un espace avant et après!: ( ! p) so! se démarque. Mais je limiterais cette utilisation aux types entiers, y compris les pointeurs. J’utiliserais == pour les points flottants, car cela vous fera réfléchir, vous et les autres, si 0.0 == p est vraiment approprié, par opposition à la spécification d’une tolérance.

Si p est une instance d’une classe, ( ! p) devrait être utilisé en définissant operator! éviter une conversion implicite avec 0.0 == p .

Si la langue est C et si p est un pointeur, alors si (p) et si (! P) doivent être évités.

C (le langage) ne spécifie pas que le pointeur nul sera boolean false. Cela dit que 0 converti en un pointeur (implicitement ou explicitement) donnera le pointeur nul.

Par conséquent, tester p plutôt que p == NULL n’est pas nécessairement identique, et sur certains matériels plus anciens, il ne l’est certainement pas, car le pointeur null est en réalité un pointeur sur une page de mémoire particulière.

Vous pouvez cependant garantir que 0 et donc NULL sont égaux au pointeur NULL, car C dit qu’ils doivent l’être.

Dans un conditionnel vraiment complexe, l’utilisation d’un == explicite peut aider à le rendre plus lisible. Malheureusement, cela ouvre également la porte à l’écriture de x = 0 au lieu de x == 0, mais vous pouvez éviter cela en écrivant 0 == x à la place (de sorte que 0 = x génère une erreur).

Cela pourrait aussi être une habitude d’autres langues dans lesquelles vous auriez à lancer un booléen.

la seule raison pragmatique que je vois, c’est que dans le second cas, le type de valeurs sockets en compte pour la comparaison est plus explicite (par exemple, foo == null foo est un type de type ponter,! foo ne peut pas dire s’il s’agit d’un pointeur, d’un bool , etc)

Avec if (0 == p) vous obligez la comparaison à saisir le “if scope” dans ce cas. Je veux dire, il sera clair que vous voulez le faire si p is equals 0 . En utilisant simplement (!p) ce n’est pas explicite ce que vous voulez savoir. Cela pourrait être null, false , etc.

if (Foo) et if (!Foo) semblent impliquer que Foo est une variable booléenne, du moins pour moi. Cela dit, tant que votre identifiant est suffisamment descriptif, cela ne devrait vraiment pas avoir d’importance. Je voudrais utiliser !Foo pour le nouveau code, mais suivez les conventions existantes s’il y en a. La cohérence l’emporte sur tous.