Frage

Gibt es einen Grund, die bitweisen Operatoren &, | und ^ nicht für „bool“-Werte in C++ 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 (anstatt es kurzzuschließen), also verwende ich & und |.Manchmal muss ich auch boolesche Werte akkumulieren, und &= und |= können sehr nützlich sein.

Ich habe dabei ein paar Augenbrauen hochgezogen, aber der Code ist immer noch aussagekräftig und sauberer, als er sonst wäre.Gibt es einen Grund, diese NICHT für Bools zu verwenden?Gibt es moderne Compiler, die hierfür schlechte Ergebnisse liefern?

War es hilfreich?

Lösung

|| Und && sind boolesche Operatoren und die integrierten Operatoren geben garantiert beide zurück true oder false.Nichts anderes.

|, & Und ^ sind bitweise Operatoren.Wenn der Bereich der Zahlen, mit denen Sie operieren, nur 1 und 0 ist, dann sind sie genau gleich, aber in Fällen, in denen Ihre booleschen Werte nicht unbedingt 1 und 0 sind – wie es bei der Sprache C der Fall ist – kann es zu einem bestimmten Verhalten kommen Du wolltest nicht.Zum Beispiel:

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

In C++ jedoch bool Der Typ ist garantiert nur entweder a true oder ein false (die implizit in respektive konvertiert werden 1 Und 0), also ist es aus dieser Sicht weniger besorgniserregend, aber die Tatsache, dass die Leute es nicht gewohnt sind, solche Dinge im Code zu sehen, ist ein gutes Argument dafür, es nicht zu tun.Sag nur b = b && x und sei damit fertig.

Andere Tipps

Zwei Hauptgründe.Kurz gesagt: Überlegen Sie sorgfältig;Es könnte einen guten Grund dafür geben, aber wenn es so ist, sollten Sie ihn in Ihren Kommentaren SEHR deutlich machen, weil er spröde sein kann und, wie Sie selbst sagen, die Leute es im Allgemeinen nicht gewohnt sind, Code wie diesen zu sehen.

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

Erstens, wenn Sie mit anderen Werten arbeiten als false Und true (oder 0 Und 1, als ganze Zahlen), die ^ Der Operator kann ein Verhalten einführen, das nicht einem logischen XOR 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 geht an Benutzer @Patrick, der dies zuerst geäußert hat.

Reihenfolge der Operationen

Zweite, |, &, Und ^, Als bitweise Operatoren schließen sie nicht kurz.Darüber hinaus können mehrere bitweise Operatoren, die in einer einzigen Anweisung verkettet sind – sogar mit expliziten Klammern – durch die Optimierung von Compilern neu angeordnet werden, da alle drei Operationen normalerweise kommutativ sind.Dies ist wichtig, wenn die Reihenfolge der Vorgänge wichtig 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

wird nicht immer das gleiche Ergebnis (oder den gleichen Endzustand) liefern 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, da Sie Methoden möglicherweise nicht kontrollieren können a() Und b(), oder jemand anders kommt vorbei und ändert sie später, ohne die Abhängigkeit zu verstehen, und verursacht einen bösen (und oft nur Release-Build-) Fehler.

Ich finde

a != b

ist das, was Sie wollen

Die hochgezogenen Augenbrauen sollten Ihnen genug sagen, damit Sie damit aufhören sollten.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 Bitoperationen gedacht, nicht für Bools.
Ich nehme an, du isst auch Äpfel mit der Gabel?Es funktioniert, aber es überrascht die Leute, deshalb ist es besser, es nicht zu tun.

Nachteile der Bitlevel-Operatoren.

Du fragst:

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

Ja das logische Operatoren, das sind die integrierten booleschen Operatoren auf hoher Ebene !, && Und ||, bieten folgende Vorteile:

  • Garantiert Konvertierung von Argumenten Zu bool, d.h.Zu 0 Und 1 Ordnungswert.

  • Garantiert Kurzschlussauswertung wobei die Ausdrucksauswertung stoppt, sobald das Endergebnis bekannt ist.
    Dies kann als Baumwertlogik interpretiert werden, mit WAHR, FALSCH Und Unbestimmt.

  • Lesbare Textäquivalente not, and Und or, auch wenn ich sie selbst nicht nutze.
    Wie Leser Antimony in einem Kommentar feststellt, haben auch die Bitlevel-Operatoren alternative Token, nämlich bitand, bitor, xor Und compl, aber meiner Meinung nach sind diese weniger lesbar als and, or Und not.

Einfach ausgedrückt ist jeder dieser Vorteile der High-Level-Operatoren ein Nachteil der Bitlevel-Operatoren.

Da den bitweisen Operatoren insbesondere die Argumentkonvertierung in 0/1 fehlt, erhalten Sie z.B. 1 & 20, während 1 && 2true.Auch ^, bitweise exklusiv oder, kann sich auf diese Weise schlecht verhalten.Als boolesche Werte gelten nämlich 1 und 2 als gleich true, aber als Bitmuster betrachtet sind sie unterschiedlich.


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

Anschließend erläutern Sie die Frage ein wenig.

„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.“

Nun, die bitweisen Operatoren haben es getan höhere Priorität als die logischen Operatoren.Dies bedeutet insbesondere, dass in einem gemischten Ausdruck wie z

a && b ^ c

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

Schreiben Sie stattdessen einfach

(a && b) != c

prägnanter ausdrücken, was Sie meinen.

Für das Mehrfachargument entweder oder Es gibt keinen C++-Operator, der diese Aufgabe erledigt.Zum Beispiel, wenn Sie schreiben a ^ b ^ c als das ist kein Ausdruck, der „weder noch“ sagt a, b oder c ist wahr".Stattdessen heißt es: „Eine ungerade Anzahl von a, b Und c „sind wahr“, das kann einer von ihnen sein oder alle drei…

Um das allgemeine Entweder/Oder Wann auszudrücken a, b Und c sind vom Typ bool, einfach schreiben

(a + b + c) == 1

oder, mit nicht-bool Argumente, konvertieren Sie sie in bool:

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


Benutzen &= um boolesche Ergebnisse zu akkumulieren.

Sie gehen näher darauf ein,

„Manchmal muss ich auch boolesche Werte akkumulieren, und &= Und |=? kann sehr nützlich sein.“

Nun, das entspricht der Überprüfung, ob bzw alle oder beliebig Bedingung ist erfüllt, und de Morgans Gesetz erklärt Ihnen, wie Sie von einem zum anderen gelangen.D.h.Sie brauchen nur einen davon.Könnte man im Prinzip gebrauchen *= Als ein &&=-Operator (denn der gute alte George Boole hat herausgefunden, dass logisches UND sehr leicht als Multiplikation ausgedrückt werden kann), aber ich denke, dass dies die Betreuer des Codes verwirren und vielleicht in die Irre führen würde.

Bedenken 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 die Bitebene &= bietet keine Konvertierung zu bool seines Arguments auf der rechten Seite.

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

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

Im Gegensatz zu Patricks Antwort gibt es in C++ keine ^^ Betreiber für die Durchführung eines Kurzschluss-Exklusiv- oder.Wenn Sie eine Sekunde darüber nachdenken, haben Sie eine ^^ Operator würde sowieso keinen Sinn ergeben:Beim Exklusiv-Oder hängt das Ergebnis immer von beiden Operanden ab.Allerdings ist Patricks Warnung vor Nicht-bool „Boolesche“ Typen gelten beim Vergleich gleichermaßen 1 & 2 Zu 1 && 2.Ein klassisches Beispiel hierfür ist Windows GetMessage() Funktion, die einen Tri-State zurückgibt BOOL:ungleich Null, 0, oder -1.

Benutzen & anstatt && Und | anstatt || ist kein ungewöhnlicher Tippfehler. Wenn Sie ihn also absichtlich machen, verdient er einen Kommentar mit der Begründung.

Patrick hat gute Argumente vorgebracht, und ich werde sie nicht wiederholen.Ich würde jedoch vorschlagen, „if“-Anweisungen nach Möglichkeit auf lesbares Englisch zu reduzieren, indem Sie gut benannte boolesche Variablen verwenden. Dies verwendet beispielsweise boolesche Operatoren, aber Sie können sie auch bitweise verwenden und die Bool-Werte entsprechend benennen:

bool onlyAIsTrue = (a && !b); // you could use bitwise XOR here
bool onlyBIsTrue = (b && !a); // and not need this second line
if (onlyAIsTrue || onlyBIsTrue)
{
 .. stuff ..
}

Sie denken vielleicht, dass die Verwendung eines booleschen Werts unnötig erscheint, aber er hilft vor allem bei zwei Dingen:

  • Ihr Code ist leichter zu verstehen, da der dazwischenliegende boolesche Wert für die „Wenn“-Bedingung die Absicht der Bedingung deutlicher macht.
  • Wenn Sie nicht standardmäßigen oder unerwarteten Code verwenden, z. B. bitweise Operatoren für boolesche Werte, können die Leute viel einfacher erkennen, warum Sie dies getan haben.

BEARBEITEN:Sie haben nicht ausdrücklich gesagt, dass Sie die Bedingungen für „if“-Anweisungen wünschen (obwohl dies am wahrscheinlichsten erscheint), das war meine Annahme.Aber mein Vorschlag eines booleschen Zwischenwerts bleibt bestehen.

IIRC, viele C++-Compiler warnen, wenn sie versuchen, das Ergebnis einer bitweisen Operation als Bool umzuwandeln.Sie müssten eine Typumwandlung verwenden, um den Compiler glücklich zu machen.

Die Verwendung einer bitweisen Operation in einem if-Ausdruck würde die gleiche Kritik hervorrufen, wenn auch möglicherweise nicht vom Compiler.Jeder Wert ungleich Null wird als wahr angesehen, sodass etwa „wenn (7 & 3)“ wahr ist.Dieses Verhalten mag in Perl akzeptabel sein, aber C/C++ sind sehr explizite Sprachen.Ich denke, die Spock-Augenbraue ist eine Sorgfaltspflicht.:) Ich würde „== 0“ oder „!= 0“ anhängen, um deutlich zu machen, was Ihr Ziel war.

Aber egal, es klingt nach einer persönlichen Vorliebe.Ich würde den Code mit Lint oder einem ähnlichen Tool ausführen und prüfen, ob er dies auch für eine unkluge Strategie hält.Persönlich liest es sich wie ein Codierungsfehler.

Die Verwendung bitweiser Operationen für Bool trägt dazu bei, unnötige Verzweigungsvorhersagelogik durch den Prozessor einzusparen, die sich aus einem „cmp“-Befehl ergibt, der durch logische Operationen eingebracht wird.

Das Ersetzen der logischen durch bitweise Operationen (wobei alle Operanden bool sind) generiert effizienteren Code, der das gleiche Ergebnis liefert.Die Effizienz sollte idealerweise alle Kurzschlussvorteile überwiegen, die bei der Bestellung mithilfe logischer Operationen genutzt werden können.

Dies kann dazu führen, dass der Code etwas unleserlich wird, obwohl der Programmierer ihn mit den Gründen dafür kommentieren sollte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top