Ich bin gerade auf ein Projekt mit einer ziemlich großen Codebasis gestoßen.
Ich beschäftige mich hauptsächlich mit C ++ und ein Großteil des Codes, den sie schreiben, verwendet doppelte Negation für ihre boolesche Logik.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
Ich weiß, dass diese Leute intelligente Programmierer sind. Es ist offensichtlich, dass sie dies nicht zufällig tun.
Ich bin kein erfahrener C ++ - Experte. Meine einzige Vermutung, warum sie dies tun, ist, dass sie absolut sicher stellen möchten, dass der zu bewertende Wert die tatsächliche boolesche Darstellung ist. Also negieren sie es und negieren es dann erneut, um es wieder auf seinen tatsächlichen booleschen Wert zu bringen.
Ist das richtig oder fehlt mir etwas?
Antworten:
Es ist ein Trick, in Bool zu konvertieren.
quelle
bool
Typ hatten, um das Speichern anderer Werte als1
und0
in booleschen Variablen zu vermeiden .!!
oder!=0
lösen Sie das Problem, und unter den beiden finde ich den ehemaligen Reiniger (da er bei einer größeren Anzahl von Typen funktioniert). Ich stimme auch zu, dass es keinen Grund gibt, den fraglichen Code zu verwenden.In einigen Zusammenhängen ist es tatsächlich eine sehr nützliche Redewendung. Nehmen Sie diese Makros (Beispiel aus dem Linux-Kernel). Für GCC werden sie wie folgt implementiert:
Warum müssen sie das tun? GCCs
__builtin_expect
behandelt seine Parameter alslong
und nichtbool
, daher muss es eine Form der Konvertierung geben. Da sie nicht wissen, wascond
ist, wenn sie diese Makros schreiben, ist es am allgemeinsten, einfach die!!
Redewendung zu verwenden.Sie könnten wahrscheinlich das Gleiche tun, indem sie mit 0 vergleichen, aber meiner Meinung nach ist es tatsächlich einfacher, die doppelte Negation durchzuführen, da dies einem Cast-to-Bool am nächsten kommt, den C hat.
Dieser Code kann auch in C ++ verwendet werden ... es ist eine Sache mit dem kleinsten gemeinsamen Nenner. Wenn möglich, machen Sie das, was sowohl in C als auch in C ++ funktioniert.
quelle
Die Codierer glauben, dass der Operand in Bool konvertiert wird, aber da die Operanden von && bereits implizit in Bool konvertiert sind, ist er absolut redundant.
quelle
Es ist eine Technik, um das Schreiben zu vermeiden (Variable! = 0) - dh um von einem beliebigen Typ in einen Bool zu konvertieren.
IMO-Code wie dieser hat keinen Platz in Systemen, die gewartet werden müssen - weil es sich nicht um sofort lesbaren Code handelt (daher die Frage an erster Stelle).
Code muss lesbar sein - andernfalls hinterlassen Sie ein Zeitschulden-Erbe für die Zukunft -, da es Zeit braucht, um etwas zu verstehen, das unnötig verwickelt ist.
quelle
bool(expr)
: es macht das richtige und jeder versteht die absicht auf den ersten blick.!!(expr)
ist eine doppelte Negation, die versehentlich in bool umgewandelt wird ... das ist nicht einfach.Ja, es ist richtig und nein, Sie vermissen nichts.
!!
ist eine Konvertierung in Bool. Weitere Informationen finden Sie in dieser Frage .quelle
Eine Compiler-Warnung wird umgangen. Versuche dies:
Die 'bar'-Zeile generiert unter MSVC ++ einen "Forcing-Wert zum Boolen von' true 'oder' false '(Leistungswarnung)", aber die' baz'-Zeile schleicht sich gut durch.
quelle
bool
Typ nicht kennt - alles ist als0
oder1
in einem codiertint
.Ist Betreiber! überladen?
Wenn nicht, tun sie dies wahrscheinlich, um die Variable in einen Bool zu konvertieren, ohne eine Warnung zu erzeugen. Dies ist definitiv keine Standardmethode.
quelle
Legacy - C - Entwickler hatten keinen Booleschen Typen, so dass sie oft
#define TRUE 1
und#define FALSE 0
dann beliebige numerische Datentypen für Boolesche Vergleiche verwendet. Jetzt, da wir es habenbool
, werden viele Compiler Warnungen ausgeben, wenn bestimmte Arten von Zuweisungen und Vergleichen unter Verwendung einer Mischung aus numerischen Typen und booleschen Typen durchgeführt werden. Diese beiden Verwendungen kollidieren schließlich, wenn Sie mit Legacy-Code arbeiten.Um dieses Problem zu umgehen, verwenden einige Entwickler die folgende boolesche Identität:
!num_value
gibtbool true
if zurücknum_value == 0
;false
Andernfalls.!!num_value
gibtbool false
if zurücknum_value == 0
;true
Andernfalls. Die einzelne Negation reicht aus, umnum_value
zu konvertierenbool
; Die doppelte Negation ist jedoch erforderlich, um den ursprünglichen Sinn des Booleschen Ausdrucks wiederherzustellen.Dieses Muster ist als Redewendung bekannt , dh etwas, das häufig von Personen verwendet wird, die mit der Sprache vertraut sind. Daher sehe ich es nicht so sehr als Anti-Muster, wie ich es tun würde
static_cast<bool>(num_value)
. Die Besetzung liefert möglicherweise die richtigen Ergebnisse, aber einige Compiler geben dann eine Leistungswarnung aus, sodass Sie sich noch darum kümmern müssen.Der andere Weg, dies anzugehen, ist zu sagen ,
(num_value != FALSE)
. Ich bin auch damit einverstanden, aber alles in allem!!num_value
ist es weit weniger ausführlich, kann klarer sein und ist nicht verwirrend, wenn Sie es das zweite Mal sehen.quelle
!!
wurde verwendet, um mit ursprünglichem C ++ umzugehen, das keinen booleschen Typ hatte (wie auch C nicht).Beispiel Problem:
Im Inneren
if(condition)
, diecondition
auf die Bedürfnisse bis zu einem gewissen Art wie zu beurteilendouble, int, void*
, etc., aber nicht ,bool
da es noch nicht vorhanden.Angenommen, eine Klasse existiert
int256
(eine 256-Bit-Ganzzahl) und alle Ganzzahlkonvertierungen / -umwandlungen wurden überladen.Um zu testen, ob
x
"wahr" oder nicht Null ist,if (x)
würdex
in eine ganze Zahl konvertiert und dann bewertet, ob diesint
nicht Null ist. Eine typische Überladung von(int) x
würde nur die LSbits von zurückgebenx
.if (x)
testete dann nur die LSbits vonx
.Aber C ++ hat den
!
Operator. Eine Überlastung!x
würde typischerweise alle Bits von auswertenx
. Es wird also verwendet, um zur nicht invertierten Logik zurückzukehrenif (!!x)
.Ref Haben ältere Versionen von C ++ den Operator "int" einer Klasse verwendet, als sie die Bedingung in einer "if ()" - Anweisung ausgewertet haben?
quelle
Wie Marcin erwähnte, könnte es durchaus wichtig sein, ob eine Überlastung des Bedieners im Spiel ist. Andernfalls spielt es in C / C ++ keine Rolle, außer wenn Sie eines der folgenden Dinge tun:
direkter Vergleich mit
true
(oder in C so etwas wie einemTRUE
Makro), was fast immer eine schlechte Idee ist. Beispielsweise:if (api.lookup("some-string") == true) {...}
Sie möchten einfach etwas in einen strengen 0/1-Wert konvertieren. In C ++
bool
wird dies implizit durch eine Zuweisung an a ausgeführt (für die Dinge, in die implizit konvertierbar istbool
). In C oder wenn Sie es mit einer Nicht-Bool-Variablen zu tun haben, ist dies eine Redewendung, die ich gesehen habe, aber ich bevorzuge die(some_variable != 0)
Variante selbst.Ich denke, im Kontext eines größeren booleschen Ausdrucks werden die Dinge einfach durcheinander gebracht.
quelle
Wenn die Variable vom Objekttyp ist, hat sie möglicherweise ein! Operator definiert, aber keine Umwandlung in Bool (oder schlimmer noch eine implizite Umwandlung in Int mit unterschiedlicher Semantik. Wenn Sie den Operator! zweimal aufrufen, wird eine Konvertierung in Bool durchgeführt, die auch in seltsamen Fällen funktioniert.
quelle
Es ist richtig, aber in C hier sinnlos - 'if' und '&&' würden den Ausdruck ohne das '!!' genauso behandeln.
Der Grund dafür in C ++ ist vermutlich, dass '&&' überladen sein könnte. Aber dann könnte '!', So dass es nicht wirklich garantiert, dass Sie einen Bool bekommen, ohne den Code für die Typen von
variable
und zu überprüfenapi.call
. Vielleicht könnte jemand mit mehr C ++ - Erfahrung erklären; Vielleicht ist es eine tiefgreifende Verteidigungsmaßnahme, keine Garantie.quelle
if
oder verwendet&&
werden. Die Verwendung!!
kann jedoch bei einigen Compilern hilfreich sein, wenn sieif (!!(number & mask))
durch ersetzt werdenbit triggered = !!(number & mask); if (triggered)
. Bei einigen eingebetteten Compilern mit Bittypen ergibt die Zuweisung von z. B. 256 zu einem Bittyp Null. Ohne die!!
ist die scheinbar sichere Transformation (Kopieren derif
Bedingung in eine Variable und anschließendes Verzweigen) nicht sicher.Vielleicht haben die Programmierer so etwas gedacht ...
!! myAnswer ist boolesch. Im Kontext sollte es boolesch werden, aber ich liebe es einfach, Dinge zu knallen, um sicherzugehen, denn es war einmal ein mysteriöser Fehler, der mich gebissen hat, und ich habe ihn getötet.
quelle
Dies kann ein Beispiel für den Double-Bang-Trick sein. Weitere Informationen finden Sie unter The Safe Bool Idiom . Hier fasse ich die erste Seite des Artikels zusammen.
In C ++ gibt es eine Reihe von Möglichkeiten, Boolesche Tests für Klassen bereitzustellen.
Wir können die Klasse testen,
Wird
opereator bool
jedoch als unsicher angesehen, da es unsinnige Operationen wietest << 1;
oder zulässtint i=test
.Die Implementierung ist trivial,
Die zwei idiomatischen Möglichkeiten zum Testen von
Testable
Objekten sindDie erste Version
if (!!test)
ist das, was manche Leute den Doppelknall-Trick nennen .quelle
explicit operator bool
damit die implizite Konvertierung in andere Integraltypen verhindert werden.