Je viens juste d'arriver sur un projet avec une base de code assez énorme.
Je travaille principalement avec C ++ et une grande partie du code qu'ils écrivent utilise la double négation pour leur logique booléenne.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
Je sais que ces types sont des programmeurs intelligents, il est évident qu'ils ne le font pas par accident.
Je ne suis pas un expert C ++ chevronné, ma seule estimation de la raison pour laquelle ils font cela est qu'ils veulent s'assurer que la valeur évaluée est la représentation booléenne réelle. Alors ils le nient, puis le nient à nouveau pour le ramener à sa valeur booléenne réelle.
Est-ce correct ou est-ce que je manque quelque chose?
Réponses:
C'est une astuce pour convertir en booléen.
la source
bool
type, pour éviter de stocker des valeurs autres que1
et0
dans des variables booléennes.!!
ou!=0
résout le problème, et parmi les deux, je trouve l'ancien nettoyeur (car il fonctionnera sur un plus grand nombre de types). Je reconnais également qu'il n'y a aucune raison d'utiliser l'un ou l'autre dans le code en question.C'est en fait un idiome très utile dans certains contextes. Prenez ces macros (exemple du noyau Linux). Pour GCC, ils sont implémentés comme suit:
Pourquoi doivent-ils faire cela? GCC
__builtin_expect
traite ses paramètres commelong
et nonbool
, il doit donc y avoir une forme de conversion. Comme ils ne savent pas ce quecond
c'est quand ils écrivent ces macros, il est plus général d'utiliser simplement l'!!
idiome.Ils pourraient probablement faire la même chose en comparant avec 0, mais à mon avis, il est en fait plus simple de faire la double négation, car c'est le plus proche d'un cast-to-bool que C a.
Ce code peut également être utilisé en C ++ ... c'est une chose au plus petit dénominateur commun. Si possible, faites ce qui fonctionne à la fois en C et C ++.
la source
Les codeurs pensent qu'il convertira l'opérande en booléen, mais comme les opérandes de && sont déjà implicitement convertis en booléen, il est totalement redondant.
la source
C'est une technique pour éviter d'écrire (variable! = 0) - c'est-à-dire pour convertir de quelque type que ce soit en booléen.
Un code IMO comme celui-ci n'a pas sa place dans les systèmes qui doivent être maintenus - car ce n'est pas un code immédiatement lisible (d'où la question en premier lieu).
Le code doit être lisible - sinon vous laissez un héritage de dette temporelle pour l'avenir - car il faut du temps pour comprendre quelque chose qui est inutilement alambiqué.
la source
bool(expr)
: il fait la bonne chose et tout le monde comprend l'intention à première vue.!!(expr)
est une double négation, qui se convertit accidentellement en booléen ... ce n'est pas simple.Oui c'est correct et non vous ne manquez pas quelque chose.
!!
est une conversion en booléen. Voir cette question pour plus de discussion.la source
Il évite un avertissement du compilateur. Essaye ça:
La ligne 'bar' génère une «valeur de forçage à booléen 'true' ou 'false' (avertissement de performance)» sur MSVC ++, mais la ligne 'baz' se faufile très bien.
la source
bool
type - tout est codé en tant que0
ou1
dans un fichierint
.Est opérateur! surchargé?
Sinon, ils le font probablement pour convertir la variable en booléen sans produire d'avertissement. Ce n'est certainement pas une manière standard de faire les choses.
la source
Les développeurs C avaient hérité aucun type Boolean, ils souvent
#define TRUE 1
et#define FALSE 0
puis utiliser les types de données numériques arbitraires pour des comparaisons booléennes. Maintenant que nous l'avons faitbool
, de nombreux compilateurs émettront des avertissements lorsque certains types d'affectations et de comparaisons sont effectués en utilisant un mélange de types numériques et de types booléens. Ces deux usages finiront par entrer en conflit lorsque vous travaillez avec du code hérité.Pour contourner ce problème, certains développeurs utilisent l'identité booléenne suivante:
!num_value
renvoiebool true
ifnum_value == 0
;false
autrement.!!num_value
renvoiebool false
sinum_value == 0
;true
autrement. La négation seule est suffisante pour convertirnum_value
àbool
; cependant, la double négation est nécessaire pour restaurer le sens original de l'expression booléenne.Ce modèle est connu comme un idiome , c'est-à-dire quelque chose de communément utilisé par des personnes familières avec la langue. Par conséquent, je ne le vois pas comme un anti-modèle, autant que je le voudrais
static_cast<bool>(num_value)
. La distribution pourrait très bien donner les résultats corrects, mais certains compilateurs émettent alors un avertissement de performances, vous devez donc toujours résoudre ce problème.L'autre façon d'aborder c'est - à - dire
(num_value != FALSE)
. Je suis d'accord avec cela aussi, mais dans l'ensemble,!!num_value
c'est beaucoup moins verbeux, peut-être plus clair et ne prête pas à confusion la deuxième fois que vous le voyez.la source
!!
a été utilisé pour gérer le C ++ original qui n'avait pas de type booléen (comme le C).Exemple de problème:
À l'intérieur
if(condition)
, lescondition
besoins d'évaluer à un type commedouble, int, void*
, etc., mais pasbool
car il n'existe pas encore.Supposons qu'une classe existe
int256
(un entier de 256 bits) et que toutes les conversions / transtypages d'entiers ont été surchargés.Pour tester si
x
était "vrai" ou non nul,if (x)
convertiraitx
en un entier et ensuite évaluer si ceint
n'était pas zéro. Une surcharge typique de(int) x
renverrait uniquement les LSbits dex
.if (x)
testait alors uniquement les LSbits dex
.Mais C ++ a l'
!
opérateur. Un surchargé!x
évaluerait généralement tous les bits dex
. Donc, pour revenir à la logique non inverséeif (!!x)
est utilisé.Ref Les anciennes versions de C ++ utilisaient-elles l'opérateur `int` d'une classe lors de l'évaluation de la condition dans une instruction` if () `?
la source
Comme Marcin l'a mentionné, cela pourrait bien avoir une importance si la surcharge des opérateurs est en jeu. Sinon, en C / C ++, cela n'a pas d'importance sauf si vous faites l'une des choses suivantes:
comparaison directe avec
true
(ou en C quelque chose comme uneTRUE
macro), ce qui est presque toujours une mauvaise idée. Par exemple:if (api.lookup("some-string") == true) {...}
vous voulez simplement quelque chose converti en une valeur stricte 0/1. En C ++, une affectation à a le
bool
fera implicitement (pour les choses qui sont implicitement convertibles enbool
). En C ou si vous avez affaire à une variable non booléenne, c'est un idiome que j'ai vu, mais je préfère la(some_variable != 0)
variété moi-même.Je pense que dans le contexte d'une expression booléenne plus large, cela encombre simplement les choses.
la source
Si la variable est de type objet, elle peut avoir un! opérateur défini mais pas de conversion en bool (ou pire, une conversion implicite en int avec une sémantique différente. L'appel de l'opérateur! deux fois entraîne une conversion en bool qui fonctionne même dans des cas étranges.
la source
C'est correct mais, en C, inutile ici - 'if' et '&&' traiteraient l'expression de la même manière sans le '!!'.
La raison de faire cela en C ++, je suppose, est que «&&» pourrait être surchargé. Mais alors, '!' Pourrait l'être aussi, donc cela ne garantit pas vraiment que vous obteniez un booléen, sans regarder le code pour les types de
variable
etapi.call
. Peut-être que quelqu'un avec plus d'expérience C ++ pourrait expliquer; il s'agit peut-être d'une sorte de mesure de défense en profondeur, et non d'une garantie.la source
if
ou&&
, mais l'utilisation!!
peut aider sur certains compilateurs si elleif (!!(number & mask))
est remplacée parbit triggered = !!(number & mask); if (triggered)
; sur certains compilateurs embarqués avec des types de bits, attribuer par exemple 256 à un type de bit donnera zéro. Sans le!!
, la transformation apparemment sûre (copie de laif
condition dans une variable puis branchement) ne sera pas sûre.Peut-être que les programmeurs pensaient à quelque chose comme ça ...
!! myAnswer est booléen. Dans le contexte, cela devrait devenir booléen, mais j'adore tout faire pour être sûr, car il était une fois un bug mystérieux qui m'a mordu, et bang bang, je l'ai tué.
la source
Cela peut être un exemple de l' astuce du double bang , voir The Safe Bool Idiom pour plus de détails. Ici, je résume la première page de l'article.
En C ++, il existe plusieurs façons de fournir des tests booléens pour les classes.
Nous pouvons tester la classe,
Cependant,
opereator bool
est considéré comme dangereux car il permet des opérations absurdes telles quetest << 1;
ouint i=test
.La mise en œuvre est triviale,
Les deux manières idiomatiques de tester un
Testable
objet sontLa première version
if (!!test)
est ce que certains appellent le truc du double bang .la source
explicit operator bool
pour empêcher la conversion implicite vers d'autres types intégraux.