108 Stimmen

Bitweise Operatoren für Boolesche Operatoren in C++ verwenden

Gibt es einen Grund, die bitweisen Operatoren &, | und ^ für "bool"-Werte in C++ nicht zu verwenden?

Manchmal stoße ich auf Situationen, in denen ich möchte, dass genau eine von zwei Bedingungen wahr ist (XOR), also füge ich einfach den Operator ^ in einen bedingten Ausdruck ein. Manchmal möchte ich auch, dass alle Teile einer Bedingung ausgewertet werden, unabhängig davon, ob das Ergebnis wahr ist oder nicht (anstelle eines Kurzschlusses), daher verwende ich & und |. Manchmal muss ich auch boolesche Werte akkumulieren, wobei &= und |= sehr nützlich sein können.

Ich habe ein paar hochgezogene Augenbrauen bekommen, als ich dies tat, aber der Code ist immer noch sinnvoll und sauberer als er es sonst wäre. Gibt es einen Grund, diese nicht für bools zu verwenden? Gibt es moderne Compiler, die in diesem Fall schlechte Ergebnisse liefern?

0 Stimmen

Wenn Sie seit dem Stellen dieser Frage ausreichend viel über C++ gelernt haben, sollten Sie zurückkommen und die aktuelle Antwort zurücknehmen und die Antwort von Patrick Johnmeyer akzeptieren, da sie den Unterschied zwischen Kurzschlüssen korrekt erklärt.

0 Stimmen

Allgemeine Bemerkung, weil die Leute sich fragen, ob dies eine gute Idee ist. Wenn man sich um die Verzweigungsabdeckung von Unit-Tests kümmert, dann ist eine Reduzierung der Verzweigungen wünschenswert. Bitweise Operatoren sind dafür nützlich.

71voto

Patrick Punkte 86090

|| y && sind boolesche Operatoren, und die eingebauten Operatoren geben garantiert entweder true o false . Sonst nichts.

| , & y ^ sind bitweise Operatoren. Wenn der Bereich der Zahlen, auf denen Sie operieren, nur 1 und 0 ist, dann sind sie genau dasselbe, aber in Fällen, in denen Ihre Booleschen Operatoren nicht strikt 1 und 0 sind - wie es in der Sprache C der Fall ist - können Sie mit einem Verhalten enden, das Sie nicht wollten. Zum Beispiel:

BOOL two = 2;
BOOL one = 1;
BOOL and = two & one;   //and = 0
BOOL cand = two && one; //cand = 1

In C++ hingegen ist die bool Typ ist garantiert nur entweder ein true oder eine false (die sich jeweils implizit in 1 y 0 Die Tatsache, dass die Leute nicht daran gewöhnt sind, solche Dinge im Code zu sehen, ist jedoch ein gutes Argument dafür, es nicht zu tun. Sagen Sie einfach b = b && x und damit fertig sein.

0 Stimmen

In C++ gibt es keinen logischen Xor-Operator ^^. Für beide Argumente als bools bewirkt != dasselbe, kann aber gefährlich sein, wenn eines der beiden Argumente kein bool ist (wie es bei der Verwendung von ^ für ein logisches xor der Fall wäre). Bin mir nicht sicher, wie das akzeptiert wurde...

1 Stimmen

Im Nachhinein betrachtet war das ziemlich dumm. Jedenfalls habe ich das Beispiel durch ein && ersetzt, um das Problem zu beheben. Ich schwöre, dass ich in der Vergangenheit schon einmal ^^ verwendet habe, aber das muss nicht der Fall gewesen sein.

3 Stimmen

C hat seit 10 Jahren einen bool-Typ, der nur 0 oder 1 sein kann. _Bool

37voto

Patrick Johnmeyer Punkte 28962

Zwei Hauptgründe. Kurz gesagt, denken Sie sorgfältig darüber nach; es könnte einen guten Grund dafür geben, aber wenn es einen gibt, seien Sie SEHR explizit in Ihren Kommentaren, denn es kann spröde sein und, wie Sie selbst sagen, sind die Leute im Allgemeinen nicht daran gewöhnt, solchen Code zu sehen.

Bitweises xor != Logisches xor (außer für 0 und 1)

Erstens, wenn Sie mit anderen Werten arbeiten als false y true (oder 0 y 1 als ganze Zahlen), die ^ Operator kann ein Verhalten einführen, das einem logischen xor nicht entspricht. Zum Beispiel:

int one = 1;
int two = 2;

// bitwise xor
if (one ^ two)
{
  // executes because expression = 3 and any non-zero integer evaluates to true
}

// logical xor; more correctly would be coded as
//   if (bool(one) != bool(two))
// but spelled out to be explicit in the context of the problem
if ((one && !two) || (!one && two))
{
  // does not execute b/c expression = ((true && false) || (false && true))
  // which evaluates to false
}

Dank an den Benutzer @Patrick, der dies als Erster zum Ausdruck brachte.

Reihenfolge der Maßnahmen

Zweitens, | , & y ^ als bitweise Operatoren keinen Kurzschluss verursachen. Außerdem können mehrere bitweise Operatoren, die in einer einzigen Anweisung aneinandergereiht sind - sogar mit expliziten Klammern - von optimierenden Compilern neu geordnet werden, da alle 3 Operationen normalerweise kommutativ sind. Dies ist wichtig, wenn die Reihenfolge der Operationen von Bedeutung ist.

Mit anderen Worten

bool result = true;
result = result && a() && b();
// will not call a() if result false, will not call b() if result or a() false

führt nicht immer zu demselben Ergebnis (oder Endzustand) wie

bool result = true;
result &= (a() & b());
// a() and b() both will be called, but not necessarily in that order in an
// optimizing compiler

Dies ist besonders wichtig, weil Sie möglicherweise keine Kontrolle über die Methoden a() y b() oder jemand anderes kommt und ändert sie später, ohne die Abhängigkeit zu verstehen, und verursacht einen unangenehmen (und oft nur in der Release-Build-Version auftretenden) Fehler.

1 Stimmen

Nicht wirklich ein fairer Vergleich, wenn man in einem Fall nach bool castet und im anderen Fall nicht... Die Besetzung zu bool in beiden Fällen ist, was würde es funktionieren, und warum es anfällig ist (weil Sie es zu erinnern haben).

0 Stimmen

Die Erklärung des Kurzschlusses ist der Grund, warum dies unbedingt die akzeptierte Antwort sein sollte; Patricks Antwort (äh... der andere Patrick, der einfach Patrick heißt) ist völlig falsch, wenn er sagt: "Wenn der Bereich der Zahlen, mit denen man operiert, nur 1 und 0 ist, dann sind sie genau gleich".

14voto

kokos Punkte 41886

Die hochgezogenen Augenbrauen sollten Ihnen genug sagen, um es nicht mehr zu tun. Sie schreiben den Code nicht für den Compiler, Sie schreiben ihn zuerst für Ihre Programmierkollegen und dann für den Compiler. Selbst wenn die Compiler funktionieren, ist es nicht das, was Sie wollen, andere Leute zu überraschen - bitweise Operatoren sind für Bit-Operationen, nicht für Bools.
Ich nehme an, Sie essen Äpfel auch mit einer Gabel? Es funktioniert, aber es überrascht die Leute, also ist es besser, es nicht zu tun.

3 Stimmen

Ja, das sollte die wichtigste Antwort sein. Folgen Sie dem Prinzip der geringsten Überraschung. Code, der ungewöhnliche Dinge tut, ist schwieriger zu lesen und zu verstehen, und Code wird viel öfter gelesen als geschrieben. Verwenden Sie keine netten Tricks wie diesen.

1 Stimmen

Ich bin hier, weil mein Kollege den bitweisen "und"-Operator für bool verwendet hat. Und jetzt verbringe ich meine Zeit damit zu verstehen, ob das richtig ist oder nicht. Wenn er das nicht getan hätte, würde ich jetzt etwas Sinnvolleres machen -_-. Wenn Sie die Zeit Ihrer Kollegen zu schätzen wissen, verwenden Sie bitte keine bitweisen Operatoren für bool!

12voto

Mark Borgerding Punkte 7537

Ich denke

a != b

ist das, was Sie wollen

1 Stimmen

Dies ist richtig, +1. Aber es gibt keine zuweisende Version dieses Operators ( !== sozusagen). Wenn Sie also das XOR einer Folge von bool Werte müssten Sie schreiben acc = acc!= condition(i); in einem Schleifenkörper. Der Compiler kann dies wahrscheinlich so effizient handhaben, als ob !== existiert, aber manche finden das nicht schön und bevorzugen die Alternative, die Booleschen Werte als ganze Zahlen zu addieren und dann zu prüfen, ob die Summe ungerade ist.

10voto

Cheers and hth. - Alf Punkte 138555

Nachteile der Bitlevel-Operatoren.

Sie fragen:

"Gibt es einen Grund, die bitweisen Operatoren nicht zu verwenden? & , | y ^ für "bool"-Werte in C++? "

Ja, die logische Operatoren d.h. die eingebauten booleschen Operatoren auf hoher Ebene ! , && y || bieten die folgenden Vorteile:

  • Garantiert Umwandlung von Argumenten a bool d.h. zu 0 y 1 Ordinalwert.

  • Garantiert Kurzschlussauswertung wobei die Auswertung des Ausdrucks endet, sobald das Endergebnis bekannt ist.
    Dies kann als eine Baum-Wert-Logik interpretiert werden, mit Wahr , Falsch y Unbestimmt .

  • Lesbare textliche Entsprechungen not , and y or auch wenn ich sie nicht selbst verwende.
    Wie der Leser Antimony in einem Kommentar anmerkt, haben auch die Bitlevel-Operatoren alternative Token, nämlich bitand , bitor , xor y compl aber meiner Meinung nach sind diese weniger gut lesbar als and , or y not .

Einfach ausgedrückt, ist jeder dieser Vorteile der Operatoren auf hoher Ebene ein Nachteil der Operatoren auf Bitebene.

Da die bitweisen Operatoren nicht in 0/1 umgewandelt werden können, erhalten Sie z. B. 1 & 20 , während 1 && 2true . Auch ^ , bitweise exklusive oder, kann sich auf diese Weise falsch verhalten. Als boolesche Werte betrachtet sind 1 und 2 dasselbe, nämlich true , aber als Bitmuster sind sie anders.


Wie man logisch ausdrückt entweder/oder in C++.

Dann geben Sie ein paar Hintergrundinformationen zur Frage,

"Ich stoße manchmal auf Situationen, in denen ich möchte, dass genau eine von zwei Bedingungen wahr ist (XOR), also füge ich den ^-Operator einfach in einen bedingten Ausdruck ein."

Nun, die bitweisen Operatoren haben höherer Vorrang als die logischen Operatoren. Dies bedeutet insbesondere, dass in einem gemischten Ausdruck wie

a && b ^ c

erhalten Sie das vielleicht unerwartete Ergebnis a && (b ^ c) .

Schreiben Sie stattdessen einfach

(a && b) != c

präziser auszudrücken, was Sie meinen.

Für das Mehrfachargument entweder/oder es gibt keinen C++-Operator, der diese Aufgabe erfüllt. Wenn Sie zum Beispiel schreiben a ^ b ^ c dann ist das kein Ausdruck, der sagt "entweder a , b o c wahr ist". Stattdessen heißt es: "Eine ungerade Anzahl von a , b y c wahr sind", was 1 von ihnen oder alle 3 sein können

Um das allgemeine Entweder-Oder auszudrücken, wenn a , b y c sind vom Typ bool schreiben Sie einfach

(a + b + c) == 1

oder, bei nicht bool Argumente, konvertieren Sie sie in bool :

(!!a + !!b + !!c) == 1

Verwendung von &= um boolesche Ergebnisse zu akkumulieren.

Sie führen weiter aus,

"Ich muss auch manchmal boolesche Werte akkumulieren, und &= y |=? kann sehr nützlich sein."

Nun, dies entspricht der Überprüfung, ob jeweils alle o jede Bedingung erfüllt ist, und de-Morgansches Gesetz sagt Ihnen, wie Sie von einem zum anderen kommen. Das heißt, Sie brauchen nur einen von beiden. Sie könnten im Prinzip Folgendes verwenden *= als &&= -Operator (denn wie der gute alte George Boole entdeckte, kann logisches UND sehr leicht als Multiplikation ausgedrückt werden), aber ich denke, dass dies die Betreuer des Codes verwirren und vielleicht in die Irre führen würde.

Beachten Sie auch:

struct Bool
{
    bool    value;

    void operator&=( bool const v ) { value = value && v; }
    operator bool() const { return value; }
};

#include <iostream>

int main()
{
    using namespace std;

    Bool a  = {true};
    a &= true || false;
    a &= 1234;
    cout << boolalpha << a << endl;

    bool b = {true};
    b &= true || false;
    b &= 1234;
    cout << boolalpha << b << endl;
}

Ausgabe mit Visual C++ 11.0 und g++ 4.7.1:

true
false

Der Grund für die unterschiedlichen Ergebnisse ist, dass der Bitlevel &= bietet keine Umwandlung in bool seines Arguments auf der rechten Seite.

Welches dieser Ergebnisse wünschen Sie sich also für Ihre Verwendung von &= ?

Wenn ersteres, true dann definieren Sie besser einen Operator (z. B. wie oben) oder eine benannte Funktion, oder verwenden Sie eine explizite Umwandlung des Ausdrucks auf der rechten Seite, oder schreiben Sie die Aktualisierung vollständig.

0 Stimmen

Bitweise Operatoren haben auch Textäquivalente

0 Stimmen

@Antimony: Ich habe diesen Kommentar zuerst nicht verstanden, aber ja, die Bitlevel-Operationen haben alternative Token bitand , bitor , xor y compl . Ich denke, deshalb habe ich die Bezeichnung "lesbar" verwendet. Natürlich ist die Lesbarkeit von z.B. compl 42 ist subjektiv. ;-)

0 Stimmen

Soweit ich weiß, können logische Operatoren kann mit anderen Argumenttypen überladen werden (obwohl sie das normalerweise nicht tun), so dass der erste Punkt "garantierte Umwandlung von Argumenten in bool " ist nur eine Folge von Konventionen, keine Garantie, die die Sprache C++ tatsächlich bietet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X