Warum '&&' und nicht '&'?


135

Warum ist &&vorzuziehen &und ||vorzuziehen |?

Ich habe jemanden gefragt, der seit Jahren programmiert, und seine Erklärung war:

Zum Beispiel in if (bool1 && bool2 && bool3) { /*DoSomething*/ }, bool1muss dafür Test wahr sein , bool2die , bevor sie zu wahr zu sein hat bool3, etc. Wenn ich einen einzelnen benutzt hatte , &anstatt es auf die Probe keine Ordnung ist , auch wenn sie alle müssen richtig sein zu Fahren Sie mit der nächsten Zeile fort. Warum ist das überhaupt wichtig?

Hinweis: Ich möchte darauf hinweisen, dass ich das Programmieräquivalent eines Kleinkindes bin und dies keine ernsthafte oder dringende Frage ist. Es geht eher darum zu verstehen, warum Dinge auf eine bestimmte Art und Weise getan werden sollten, im Gegensatz zu einer anderen.


55
& und && | und || sind völlig andere Betreiber
Felice Pollano

3
Retagged, da dies nicht nur für C # gilt
Jonathan Dickinson

12
Umgekehrt, da die Antworten bereits spezifisch für C # sind und das Innenleben in anderen Sprachen, die im Allgemeinen das gleiche Konzept haben, etwas abweichen kann.
Daniel Hilgarth

8
@ Felice: Sie sind unterschiedlich, aber kaum völlig unterschiedlich. Sie sind in der Tat sehr ähnlich: x & yund x && ywerden immer zum gleichen Ergebnis ausgewertet, wenn x und y Ausdrücke vom booleschen Typ sind. Tatsächlich scheint der einzige Unterschied in diesem Fall darin zu bestehen, dass in x & y, y immer ausgewertet wird.
Joren

1
@slawekin: Ich würde vorschlagen, die Antworten durchzulesen. Einige schreiben ausführlich über die Leistungsunterschiede. Die Antwort könnte Sie jedoch überraschen.
Abel

Antworten:


183

In den meisten Fällen &&und ||werden bevorzugt über &und |weil die ersteren sind kurzgeschlossen, so dass die Bewertung so schnell aufgehoben wird , wenn das Ergebnis klar ist.

Beispiel:

if(CanExecute() && CanSave())
{
}

Wenn zurückgegeben wird, CanExecutelautet falseder vollständige Ausdruck falseunabhängig vom Rückgabewert von CanSave. Aus diesem Grund CanSavewird nicht ausgeführt.

Dies ist unter folgenden Umständen sehr praktisch:

string value;
if(dict.TryGetValue(key, out value) && value.Contains("test"))
{
    // Do Something
}

TryGetValueGibt zurück, falsewenn der angegebene Schlüssel nicht im Wörterbuch gefunden wird. Wegen des Kurzschlusses von &&, value.Contains("test")wird nur ausgeführt, wenn TryGetValuezurückkehrt trueund somit valuenicht null. Wenn Sie stattdessen den bitweisen AND- Operator &verwenden würden, würden Sie einen erhalten, NullReferenceExceptionwenn der Schlüssel nicht im Wörterbuch gefunden wird, da der zweite Teil des Ausdrucks in jedem Fall ausgeführt wird.

Ein ähnliches, aber einfacheres Beispiel hierfür ist der folgende Code (wie von TJHeuvel erwähnt):

if(op != null && op.CanExecute())
{
    // Do Something
}

CanExecutewird nur ausgeführt, wenn opnicht null. Wenn dies der Fall opist null, wird der erste Teil von expression ( op != null) ausgewertet falseund die Auswertung von rest ( op.CanExecute()) wird übersprungen.

Abgesehen davon, technisch gesehen , sie sind auch anders:
&&und ||kann nur verwendet werden , auf der boolErwägung , dass &und |kann auf jedem integrierten Typ verwendet werden ( bool, int, long, sbyte, ...), weil sie bitweise Operatoren sind. &ist der bitweise UND- Operator und |der bitweise ODER- Operator.

Um genau zu sein, werden diese Operatoren ( &, |[und ^]) in C # als "logische Operatoren" bezeichnet (siehe C # -Spezifikation , Kapitel 7.11). Es gibt verschiedene Implementierungen dieser Operatoren:

  1. Für ganze Zahlen ( int, uint, longund ulong, Kapitel 7.11.1):
    Sie werden implementiert , um die bitweise Ergebnis der Operanden und dem Betreiber zu berechnen, also &ist zu implementieren , um die bitweise logische berechnen ANDusw.
  2. Für Aufzählungen (Kapitel 7.11.2):
    Sie werden implementiert, um die logische Operation des zugrunde liegenden Aufzählungstyps auszuführen.
  3. Für Bools und nullfähige Bools (Kapitel 7.11.3 und 7.11.4):
    Das Ergebnis wird nicht mit bitweisen Berechnungen berechnet. Das Ergebnis wird im Wesentlichen anhand der Werte der beiden Operanden nachgeschlagen, da die Anzahl der Möglichkeiten so gering ist.
    Da beide Werte für die Suche verwendet werden, wird diese Implementierung nicht kurzgeschlossen.

31
Dies kann auch nützlich sein, um zu überprüfen, ob etwas null ist. Zum Beispiel : if(op != null && op.CanExecute()). Da die zweite Ursache nicht bewertet wird, wenn die erste nicht wahr ist, ist dies gültig.
TJHeuvel

2
@TJHeuvel: Dies ist im Grunde die gleiche Verwendung, die ich mit meinem TryGetValueBeispiel beschrieben habe . Aber ja, es ist ein weiteres gutes Beispiel dafür.
Daniel Hilgarth

4
Gute Antwort. Vielleicht sollten Sie auch ein Beispiel hinzufügen, wie &oder |mit nicht-boolen Argumenten (dh was die Operatoren tun) zum Nutzen aller neuen Personen verwendet wird.
Zabba

81

Um sehr klar zu erklären, was dies bedeutet (obwohl die anderen Antworten darauf hinweisen - aber verwenden Sie wahrscheinlich eine Terminologie, die Sie nicht verstehen).

Der folgende Code:

if (a && b)
{
   Foo();
}

Ist wirklich dazu zusammengestellt:

if (a)
{
    if (b)
    {
        Foo();
    }
}

Wo der folgende Code genau so kompiliert wird, wie er dargestellt wird:

if (a & b)
{
   Foo();
}

Dies wird als Kurzschluss bezeichnet. Im Allgemeinen sollten Sie immer &&und ||in Ihren Bedingungen verwenden.

Bonuspunkte: Es gibt ein Szenario, in dem Sie nicht sollten. Wenn Sie sich in einer Situation befinden, in der die Leistung entscheidend ist (und dies ist Nano-Sekunden entscheidend ), verwenden Sie den Kurzschluss nur dann, wenn Sie müssen (z. B. nullPrüfen) - da ein Kurzschluss eine Verzweigung / ein Sprung ist; Dies kann zu einer falschen Vorhersage der Verzweigung Ihrer CPU führen. ein &ist viel billiger als &&. Es gibt auch ein Szenario, in dem ein Kurzschluss tatsächlich die Logik brechen kann - sehen Sie sich meine Antwort an.

Diatribe / Monolog : In Bezug auf die Zweigvorhersage, die am glücklichsten ignoriert wird. Zitat von Andy Firth (der seit 13 Jahren an Spielen arbeitet): "Dies ist möglicherweise eine niedrigere Ebene, die die Leute für nötig halten ... aber sie würden sich irren. Sie verstehen, wie die Hardware, die Sie für die Behandlung von Zweigen programmieren, dies kann." die Leistung in einem RIESIGEN Ausmaß beeinflussen ... weit mehr als die meisten Programmierer vielleicht zu schätzen wissen: Tod durch tausend Kürzungen. "

  • Spieleentwickler (und andere, die unter extremen Echtzeitbedingungen arbeiten) gehen so weit, ihre Logik neu zu strukturieren, um sie besser an den Prädiktor anzupassen. Dies zeigt sich auch im dekompilierten mscorlib-Code.
  • Nur weil .NET Sie vor solchen Dingen schützt, heißt das nicht, dass es nicht wichtig ist. Eine Verzweigungsfehlvorhersage ist bei 60 Hz schrecklich teuer; oder bei 10.000 Anfragen / Sekunde.
  • Intel hätte weder Tools, um den Ort von Fehlvorhersagen zu identifizieren, noch hätte Windows einen Leistungsindikator dafür, noch würde es ein Wort geben, um es zu beschreiben, wenn es kein Problem wäre.
  • Unwissenheit über die unteren Ebenen und die Architektur macht niemanden, der sich ihrer bewusst ist, falsch.
  • Versuchen Sie immer, die Einschränkungen der Hardware zu verstehen, an der Sie arbeiten.

Hier ist ein Maßstab für die Ungläubigen. Führen Sie den Prozess am besten in RealTime / High aus, um die Auswirkungen des Schedulers zu verringern: https://gist.github.com/1200737


7
Über die "Bonuspunkte": Wir alle kennen das Gute, das aus vorzeitiger Optimierung resultiert. :)
ein CVn

6
@Michael - deshalb ist 'Nano-Sekunden entscheidend' fett gedruckt :). AAA-Spieleentwickler sorgen sich normalerweise um solche Dinge - und Sie wissen nie, wer die Antworten lesen wird. Daher ist es immer am besten, auch die Grenz- / Extremfälle zu dokumentieren.
Jonathan Dickinson

1
Ist diese Bonusmarke für C # gültig? Ich hätte nicht gedacht, wie MSIL interpretiert wird, es sei denn, der Ausdruck wird bis zum Maschinencode kompiliert.
Jeremy McGee

7
@Jeremy MSIL wird nicht interpretiert.
Jonathan Dickinson

2
@TheD Antwort erneut prüfen - Ich habe einen Monolog hinzugefügt, warum Sie sich darüber Sorgen machen sollten. Und, zu Ihrer Information, (x && y)übersetzt dorthin, LOAD x; BRANCH_FALSE; LOAD y; BRANCH_FALSE;wohin (x & y)übersetzt wird LOAD x; LOAD y; AND; BRANCH_FALSE;. Ein Zweig gegen zwei.
Jonathan Dickinson

68

Logischer Operator ( ||und &&) vs. bitweiser Operator ( |und &).

Der wichtigste Unterschied zwischen einem logischen Operator und einem bitweisen Operator besteht darin, dass ein logischer Operator zwei Boolesche Werte verwendet und einen Booleschen Wert erzeugt, während ein bitweiser Operator zwei Ganzzahlen verwendet und eine Ganzzahl erzeugt (Hinweis: Ganzzahlen bedeuten einen beliebigen integralen Datentyp, nicht nur int).

Um pedantisch zu sein, nimmt ein bitweiser Operator ein Bitmuster (z. B. 01101011) und führt ein bitweises UND / ODER für jedes Bit durch. Wenn Sie beispielsweise zwei 8-Bit-Ganzzahlen haben:

a     = 00110010 (in decimal:    32+16+2   = 50)
b     = 01010011 (in decimal: 64+   16+2+1 = 83)
----------------
a & b = 00010010 (in decimal:       16+2   = 18)
a | b = 01110011 (in decimal: 64+32+16+2+1 = 115)

während ein logischer Operator nur funktioniert in bool:

a      = true
b      = false
--------------
a && b = false
a || b = true

Zweitens ist es oft möglich, einen bitweisen Operator für bool zu verwenden, da true und false gleich 1 bzw. 0 sind. Wenn Sie true in 1 und false in 0 übersetzen, führen Sie eine bitweise Operation durch und konvertieren Sie dann Nicht-Null zu wahr und null zu falsch; Es kommt vor, dass das Ergebnis das gleiche ist, wenn Sie gerade einen logischen Operator verwendet haben (überprüfen Sie dies auf Übung).

Ein weiterer wichtiger Unterschied besteht darin, dass ein logischer Operator kurzgeschlossen wird . So sieht man in manchen Kreisen [1] oft Leute, die so etwas tun:

if (person && person.punch()) {
    person.doVictoryDance()
}

was übersetzt bedeutet: "Wenn eine Person existiert (dh nicht null ist), versuchen Sie, sie / ihn zu schlagen, und wenn der Schlag erfolgreich ist (dh wahr zurückgibt), dann machen Sie einen Siegestanz" .

Hatten Sie stattdessen einen bitweisen Operator verwendet:

if (person & person.punch()) {
    person.doVictoryDance()
}

wird übersetzt zu: "Wenn eine Person existiert (dh nicht null ist) und der Schlag erfolgreich ist (dh wahr zurückgibt), dann mache einen Siegestanz" .

Beachten Sie, dass im kurzgeschlossenen logischen Operator der person.punch()Code möglicherweise überhaupt nicht ausgeführt wird, wenn er personnull ist. Tatsächlich würde in diesem speziellen Fall der zweite Code einen Nullreferenzfehler erzeugen, wenn er personnull ist, da er versucht aufzurufen, person.punch()unabhängig davon, ob die Person null ist oder nicht. Dieses Verhalten, den richtigen Operanden nicht auszuwerten, wird als Kurzschluss bezeichnet .

[1] Einige Programmierer werden es ablehnen, einen Funktionsaufruf zu platzieren, der einen Nebeneffekt in einem ifAusdruck hat, während es für andere eine übliche und sehr nützliche Redewendung ist.

Da ein bitweiser Operator jeweils mit 32-Bit arbeitet (wenn Sie sich auf einem 32-Bit-Computer befinden), kann dies zu einem eleganteren und schnelleren Code führen, wenn Sie eine große Anzahl von Bedingungen vergleichen müssen, z

int CAN_PUNCH = 1 << 0, CAN_KICK = 1 << 1, CAN_DRINK = 1 << 2, CAN_SIT = 1 << 3,
    CAN_SHOOT_GUNS = 1 << 4, CAN_TALK = 1 << 5, CAN_SHOOT_CANNONS = 1 << 6;

Person person;
person.abilities = CAN_PUNCH | CAN_KICK | CAN_DRINK | CAN_SIT | CAN_SHOOT_GUNS;

Place bar;
bar.rules = CAN_DRINK | CAN_SIT | CAN_TALK;

Place military;
military.rules = CAN_SHOOT_CANNONS | CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT;

CurrentLocation cloc1, cloc2;
cloc1.usable_abilities = person_abilities & bar_rules;
cloc2.usable_abilities = person_abilities & military_rules;

// cloc1.usable_abilities will contain the bit pattern that matches `CAN_DRINK | CAN_SIT`
// while cloc2.usable_abilities will contain the bit pattern that matches `CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT`

Dasselbe mit logischen Operatoren zu tun, würde eine unangenehme Anzahl von Vergleichen erfordern:

Person person;
person.can_punch = person.can_kick = person.can_drink = person.can_sit = person.can_shoot_guns = true;
person.can_shoot_cannons = false;

Place bar;
bar.rules.can_drink = bar.rules.can_sit = bar.rules.can_talk = true;
bar.rules.can_punch = bar.rules.can_kick = bar.rules.can_shoot_guns = bar.rules.can_shoot_cannons = false;

Place military;
military.rules.can_punch = military.rules.can_kick = military.rules.can_shoot_guns = military.rules.can_shoot_cannons = military.rules.can_sit = true;
military.rules.can_drink = military.rules.can_talk = false;

CurrentLocation cloc1;
bool cloc1.usable_abilities.can_punch         = bar.rules.can_punch         && person.can_punch,
     cloc1.usable_abilities.can_kick          = bar.rules.can_kick          && person.can_kick,
     cloc1.usable_abilities.can_drink         = bar.rules.can_drink         && person.can_drink,
     cloc1.usable_abilities.can_sit           = bar.rules.can_sit           && person.can_sit,
     cloc1.usable_abilities.can_shoot_guns    = bar.rules.can_shoot_guns    && person.can_shoot_guns,
     cloc1.usable_abilities.can_shoot_cannons = bar.rules.can_shoot_cannons && person.can_shoot_cannons
     cloc1.usable_abilities.can_talk          = bar.rules.can_talk          && person.can_talk;

bool cloc2.usable_abilities.can_punch         = military.rules.can_punch         && person.can_punch,
     cloc2.usable_abilities.can_kick          = military.rules.can_kick          && person.can_kick,
     cloc2.usable_abilities.can_drink         = military.rules.can_drink         && person.can_drink,
     cloc2.usable_abilities.can_sit           = military.rules.can_sit           && person.can_sit,
     cloc2.usable_abilities.can_shoot_guns    = military.rules.can_shoot_guns    && person.can_shoot_guns,
     cloc2.usable_abilities.can_talk          = military.rules.can_talk          && person.can_talk,
     cloc2.usable_abilities.can_shoot_cannons = military.rules.can_shoot_cannons && person.can_shoot_cannons;

Ein klassisches Beispiel für die Verwendung von Bitmustern und bitweisen Operatoren sind Unix / Linux-Dateisystemberechtigungen.


3
+1 für die Seite betrifft das Problem. Überrascht wurde es nicht früher erwähnt
Conrad Frix

3
Das Beispiel scheint ein bisschen gewalttätig zu sein, aber andere Antworten scheinen sich zu sehr auf Kurzschlüsse zu konzentrieren und nicht genug auf den Unterschied zwischen der Arbeit mit ganzen Zahlen und mit Booleschen Werten.
R0MANARMY

Die Funktion muss verstanden werden, bevor Implementierungsdetails (Kurzschluss / Nebenwirkungen) ins Spiel kommen. Ich bin froh, dass Sie den Hauptunterschied zwischen Boolescher und ganzzahliger Logik und nicht mit Kurzschlüssen behoben haben.
Abel

@ ROMANARMY - gewalttätig, ich liebe die Ironie, die Ihr Mönch hat.
Gute

8

Im Falle von:

if (obj != null && obj.Property == true) { }

würde wie erwartet funktionieren.

Aber:

if (obj != null & obj.Property == true) { }

könnte möglicherweise eine Nullreferenzausnahme auslösen.


2

Kurz und einfach:

1 && 2= wahr,
weil
1 = wahr (nicht Null) in C
2 = wahr (nicht Null) in C.

trueANDS logisch mit truezu geben true.

Aber

1 & 2= 0 = falsch,
weil
1 = 0001 in binär
2 = 0010 in binär

0001 UNDs bitweise mit 0010, um 0000 = 0 in Dezimalzahl zu ergeben.

Ebenso für || und | Betreiber auch ...!


2
-1: Wir sprechen hier über C # ... 1 && 2ist illegal in C #
Daniel Hilgarth

Dies ist jedoch ein äußerst wichtiges Beispiel, das erklärt, warum Sie & und && nicht einfach austauschen können (was viele Leute zu denken scheinen).
Bobobobo

1

&&ist die Kurzschlussversion von &.

Wenn wir bewerten false & true, wissen wir bereits aus dem ersten Argument, dass das Ergebnis falsch sein wird. Die &&Version des Operators gibt so schnell wie möglich ein Ergebnis zurück, anstatt den gesamten Ausdruck auszuwerten. Es gibt auch eine ähnliche Version des |Operators ||.


1
if (list.Count() > 14 && list[14] == "foo")

ist sicher

if (list.Count() > 14 & list[14] == "foo")

würde abstürzen, wenn die Liste nicht die richtige Größe hat.


Ich kann mir nicht vorstellen, dass jemand "if (list.Count ()> 14 & list [14] ==" foo ")" anstelle von "if (list.Count ()> 14 && list [14] ==" schreiben kann. foo ")". & kann in diesem Fall einfach und natürlich nicht für && verwendet werden, auch wenn & 's sicher ist (Liste [1] zum Beispiel).
Tien Do

1

C # -Betreiber sollten erklären, warum:

Wenn Sie im Wesentlichen zwei &oder zwei haben , |bedeutet dies, dass es sich eher um eine Bedingung als um eine logische handelt, sodass Sie den Unterschied zwischen den beiden erkennen können.

& Operator hat ein Beispiel für die Verwendung eines&.


Beide Links sind (effektiv) fehlerhaft (Weiterleitung zu "Visual Studio 2005 Retired-Dokumentation" ).
Peter Mortensen

1

OK, auf den Nennwert

    Boolean a = true;
    Boolean b = false;

    Console.WriteLine("a({0}) && b({1}) =  {2}", a, b, a && b);
    Console.WriteLine("a({0}) || b({1}) =  {2}", a, b, a || b);
    Console.WriteLine("a({0}) == b({1}) =  {2}", a, b, a == b);

    Console.WriteLine("a({0}) & b({1}) =  {2}", a, b, a & b);
    Console.WriteLine("a({0}) | b({1}) =  {2}", a, b, a | b);
    Console.WriteLine("a({0}) = b({1}) =  {2}", a, b, a = b);

die gleiche Antwort produzieren. Wenn Sie jedoch eine komplexere Frage haben, wie Sie gezeigt haben:

if (a and b and c and d) ..

Wenn aes nicht wahr ist und vielleicht beine Funktion ist, bei der es losgehen muss, sich mit etwas verbinden, dies bekommen, das tun, eine Entscheidung treffen ... warum sich die Mühe machen? Zeitverschwendung, Sie wissen , dass es bereits fehlgeschlagen ist. Warum die Maschine ausschalten und besonders sinnlose Arbeit leisten?

Ich habe es immer verwendet, &&weil ich das wahrscheinlichste Versagen zuerst, also weniger Berechnungen, vor dem Fortfahren gesetzt habe, wenn es keinen Sinn macht. Wenn es keine Möglichkeit gibt, weniger wahrscheinliche Entscheidungen vorherzusagen, z. B. einen Booleschen Wert, um die Ausgabe von Daten zu begrenzen, können Sie Folgendes tun:

if (limit && !MyDictionary.ContainsKey("name")) 
    continue;

Wenn nicht limit, suchen Sie nicht nach dem Schlüssel, was länger dauern kann.


1

Bei Verwendung in einem logischen Ausdruck wie einer if-Anweisung ist dies &&vorzuziehen, da die Auswertung von Ausdrücken beendet wird, sobald das erste falsche Ergebnis auftritt. Dies ist möglich, weil ein falscher Wert dazu führt, dass der gesamte Ausdruck falsch ist. Ähnlich (und wieder in logischen Ausdrücken)|| ist dies vorzuziehen, da die Auswertung von Ausdrücken beendet wird, sobald ein wahrer Ausdruck gefunden wird, da jeder wahre Wert dazu führt, dass der gesamte Ausdruck wahr ist.

Wenn jedoch die Ausdrücke or-ed oder and-ed zusammen Nebenwirkungen haben und Sie möchten, dass all diese als Ergebnis Ihres Ausdrucks auftreten (unabhängig vom Ergebnis des logischen Ausdrucks), dann &und |könnten verwendet werden. Umgekehrt können die Operatoren &&und ||als Schutz vor unerwünschten Nebenwirkungen nützlich sein (z. B. ein Nullzeiger, der das Auslösen einer Ausnahme verursacht).

Die Operatoren &und |können auch mit ganzen Zahlen verwendet werden. In diesem Fall erzeugen sie ein ganzzahliges Ergebnis, bei dem es sich um die beiden Operanden handelt, die auf Bitebene zusammen -ed oder or-ed sind. Dies kann nützlich sein, wenn die Binärbits eines ganzzahligen Werts als Array von wahren und falschen Werten verwendet werden. Um zu testen, ob ein bestimmtes Bit ein- oder ausgeschaltet ist, wird eine Bitmaske bitweise mit dem Wert versehen. Um ein Bit einzuschalten, kann dieselbe Maske bitweise mit dem Wert verknüpft werden. Zum Schluss, um ein bisschen auszuschalten, wird das bitweise Komplement (unter Verwendung ~) einer Maske bitweise und mit dem Wert bearbeitet.

int a = 0; // 0 means all bits off
a = a | 4; // set a to binary 100
if ((a & 4) != 0) {
    // will do something
}
a = a & (~4) // turn bit off again, a is now 000

In anderen Sprachen als C # muss mit den logischen und bitweisen Modi von & und | vorsichtig umgegangen werden. Im obigen Code ist der ifbedingte Ausdruck der Anweisung (a & 4) != 0eine sichere Möglichkeit, diese Bedingung auszudrücken. In vielen C-ähnlichen Sprachen können bedingte Anweisungen einfach ganzzahlige Werte von Null als falsch und ganzzahlige Werte ungleich Null als wahr behandeln. (Der Grund hierfür liegt in den verfügbaren Anweisungen für bedingte Verzweigungsprozessoren und in ihrer Beziehung zum Null-Flag, das nach jeder Ganzzahloperation aktualisiert wird.) ìfDer Test der Anweisung für Null kann also entfernt und die Bedingung auf verkürzt werden (a & 4).

Dies kann zu Verwirrung und möglicherweise sogar zu Problemen führen, wenn Ausdrücke mit bitweisen und Operator-Rückgabewerten kombiniert werden, für die keine Bits vorhanden sind. Betrachten Sie das folgende Beispiel, in dem die Nebenwirkungen von zwei Funktionen gewünscht werden, bevor Sie überprüfen, ob beide erfolgreich waren (wie von ihnen definiert, und einen Wert ungleich Null zurückgeben):

if (foo() & bar()) {
    // do something
}

Wenn in C foo()1 und bar()2 zurückgegeben wird, wird das "Etwas" nicht ausgeführt, da 1 & 2es Null ist.

C # erfordert bedingte Anweisungen if, die einen booleschen Oeprand haben sollen, und die Sprache erlaubt nicht, dass ein ganzzahliger Wert in einen booleschen Wert umgewandelt wird. Der obige Code würde also Compilerfehler erzeugen. Es würde korrekter wie folgt ausgedrückt:

if (foo() != 0 & bar() != 0) {
    // do something
}

1

Wenn Sie ein Oldtimer-C-Programmierer sind, seien Sie vorsichtig . C # hat mich wirklich überrascht.

MSDN sagt für den |Betreiber:

Binär | Operatoren sind für die Integraltypen und bool vordefiniert . Für ganzzahlige Typen | berechnet das bitweise ODER seiner Operanden. Für Bool-Operanden | berechnet das logische ODER seiner Operanden; Das heißt, das Ergebnis ist genau dann falsch, wenn beide Operanden falsch sind.

(Der Schwerpunkt liegt bei mir.) Boolesche Typen werden speziell behandelt, und in diesem Zusammenhang macht die Frage erst Sinn, und der Unterschied besteht darin, wie andere bereits in ihren Antworten dargelegt haben:

&&und ||sind kurzgeschlossen. &und |bewerten Sie beide Operanden.

und was vorzuziehen ist, hängt von vielen Dingen wie Nebenwirkungen, Leistung und Lesbarkeit des Codes ab, aber im Allgemeinen sind die Kurzschlussoperatoren auch deshalb vorzuziehen, weil sie von Menschen mit einem ähnlichen Hintergrund wie mir besser verstanden werden.

Der Grund ist: Ich würde so argumentieren: Da es in C keinen echten booleschen Typ gibt, können Sie den bitweisen Operator verwenden |und sein Ergebnis in einer if-Bedingung als wahr oder falsch bewerten lassen. Dies ist jedoch die falsche Einstellung für C #, da es bereits einen Sonderfall für boolesche Typen gibt.


0

Dies ist wichtig, denn wenn die Kosten für die Evaluierung von bool2 (zum Beispiel) hoch sind, bool1 jedoch falsch, haben Sie sich mit && over & einiges an Rechenaufwand erspart


0

Weil &&und ||für die Flusskontrolle genauso verwendet werden wie sie if/elsesind. Es geht nicht immer um Bedingungen. Es ist durchaus sinnvoll, wie zu schreiben , eine Erklärung, nicht als ein ifoder eine whilebedingte, die folgenden:

 a() && b() && c() && d();

oder auch

 w() || x() || y() || z();

Es ist nicht nur so, dass diese einfacher zu tippen sind als die entsprechenden if/elseVersionen. Sie sind auch viel einfacher zu lesen und zu verstehen.


0

&& und & bedeuten zwei sehr unterschiedliche Dinge und geben Ihnen zwei unterschiedliche Antworten.

1 && 2ergibt 1 ("wahr")
1 & 2ergibt 0 ("falsch")

&&ist ein logischer Operator - es bedeutet "wahr, wenn beide Operanden wahr sind"
&ist ein bitweiser Vergleich. Es bedeutet "Sag mir, welche der Bits in beiden Operanden gesetzt sind".


2
Die Frage betrifft C #. In C # gibt es keine Möglichkeit, eine Zahl in einen Bool umzuwandeln. 0 ist also nicht 'false' und ungleich Null ist nicht 'true'. Es gibt einfach keine Äquivalenz.
Nate CK

Um eine Zahl in Bool umzuwandeln, sagen Sie "n! = 0" (1 - wahr) und 0 (falsch) (ich nehme an ... ich bin mit C # nicht wirklich vertraut). Eigentlich wollte ich diesen Kommentar zurückziehen, da er nicht gut recherchiert ist und ich denke nicht, dass er für den vorherigen Kommentar hilfreich oder wirklich relevant ist, jetzt wo ich mehr darüber nachdenke, aber ich habe versehentlich die Eingabetaste gedrückt und jetzt glaube ich nicht, dass ich das kann storniere es also los geht's, für was auch immer es wert ist :-)
Don Hatch

1 && 2gibt einen Compilerfehler aus: "Fehler 4 Operator '&&' kann nicht auf Operanden vom Typ 'int' und 'int' angewendet werden"
Peter Mortensen

0

Der schnellste (und etwas heruntergekommenste) Weg, dies Leuten zu erklären, die dabei nicht die genauen Operationen des Codes kennen MÜSSEN, ist

&& überprüft jede dieser Bedingungen, bis eine falsche gefunden wird und das gesamte Ergebnis als falsch zurückgegeben wird

|| überprüft jede dieser Bedingungen, bis sie ein wahres Ergebnis findet und das gesamte Ergebnis als wahr zurückgibt.

& macht MATHS-basierte Apon BEIDE / ALLE Bedingungen und befasst sich mit dem Ergebnis.

| macht MATHS-basierte Apon BEIDE / ALLE Bedingungen und befasst sich mit dem Ergebnis.

Ich bin noch nie auf einen Punkt gestoßen, an dem ich & oder | verwenden musste innerhalb einer if-Anweisung. Ich benutze es meistens, um Hexadezimalwerte durch bitweise Verschiebung in seine Komponentenfarben zu zerschneiden.

Z.B:

r = fullvalue >> 0xFF & 0xFF;
g = fullvalue >> 0xF & 0xFF;
b = fullvalue & 0xFF;

Innerhalb dieser Operation zwingt "& 0xFF", nur den Binärwert zu betrachten. Ich habe persönlich keine Verwendung für | gefunden doch trotzdem.


0

Einfach,

if exp1 && exp2

Wenn exp1 ist flase , überprüfen Sie nicht exp2

aber

if exp1 & exp2

wenn exp1 ist false Oder true überprüfen Sie exp2

und selten verwenden Leute, &weil sie selten exp2 überprüfen wollen, ob exp1 istfalse

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.