Warum gibt es in C # sowohl eine kurzschließende ODER- als auch eine kurzgeschlossene Variation dieses Operators?

9

In regelmäßigen Abständen wundere ich mich darüber:

Der Kurzschluss-ODER würde immer den gleichen Wert zurückgeben, den der kurzgeschlossene ODER-Operator?

Ich gehe davon aus, dass der Kurzschluss ODER immer schneller ausgewertet wird. War der kurzgeschlossene ODER-Operator aus Gründen der Konsistenz in der C # -Sprache enthalten?

Was habe ich vermisst?

CarneyCode
quelle
9
Gleicher Rückgabewert - ja. Gleiche Nebenwirkungen - nein.
Job
2
Es sei f()eine Ausnahme auslöst, betrachten true || f()und true | f(). Sehen Sie den Unterschied? Der erstere Ausdruck wertet aus true, die Auswertung des letzteren führt dazu, dass eine Ausnahme ausgelöst wird.
Scarfridge

Antworten:

25

Beide Operanden waren für verschiedene Dinge gedacht und stammten von C, das keinen booleschen Typ hatte. Die Kurzschlussversion || funktioniert nur mit Booleschen Werten, während die Nicht-Kurzschlussversion | arbeitet mit integralen Typen, die bitweise oder. Es funktionierte zufällig als logische Nicht-Kurzschlussoperation für Boolesche Werte, die durch ein einzelnes Bit dargestellt werden und 0 oder 1 sind.

http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical

Sichern
quelle
10
+1 für den Link. Als ich diese Frage las, sagte ich: "Was?" seit afaik sind die offiziellen Namen logisch und bitweise oder und nicht Kurzschluss und Kurzschluss, die zufällig Nebenwirkungen ihrer Funktionsweise sind.
Stijn
1
+1 Ich sehe "arbeitet nur mit booleschen Operanden" - Ich habe den Unterschied möglicherweise nicht bemerkt, weil ich sowieso nur Ausdrücke verwende, die als boolesch ausgewertet werden
CarneyCode
2
Ich musste überprüfen, aber es ist tatsächlich wahr, dass der |Operator, wenn er auf zwei boolesche Werte angewendet wird, orin CIL in denselben Operator kompiliert wird wie wenn er auf zwei ganzzahlige Werte angewendet wird - im Gegensatz zu ||dem, der mit brtrueeiner Bedingung in CIL kompiliert wird springen.
Quentin-Starin
13

|(das bitweise-oder) muss für Typen wie nicht kurzgeschlossen sein int. |Dies liegt daran, dass Sie in fast allen Fällen beide Seiten eines Ausdrucks berechnen müssen, um das richtige Ergebnis zu berechnen. Was ist zum Beispiel das Ergebnis von 7 | f(x)?

Wenn f(x)nicht ausgewertet wird, können Sie nicht sagen.

Darüber hinaus wäre es inkonsistent, diesen Operator kurzzuschließen bool, wenn er nicht kurzgeschlossen ist int. Ich glaube übrigens, ich habe nie |absichtlich logische Vergleiche verwendet, und es ist sehr unpraktisch, von |einem logischen Operator zu sprechen .

|| Dies ist jedoch für logische Vergleiche gedacht, bei denen die Kurzschlussbewertung einwandfrei funktioniert.

Gleiches gilt auch für C und C ++, wo der Ursprung dieser Operatoren liegt.

Doc Brown
quelle
5

Dies ist richtig. Der Kurzschluss-ODER-Operator (||) gibt immer den gleichen Wert zurück wie der Nicht-Kurzschluss-ODER-Operator (|). (*)

Wenn jedoch der erste Operand wahr ist, bewirkt der Kurzschlussoperator keine Auswertung des zweiten Operanden, während der Nicht-Kurzschlussoperator immer eine Auswertung beider Operanden bewirkt. Dies kann sich auf die Leistung und manchmal auf Nebenwirkungen auswirken.

Es gibt also eine Verwendung für beide: Wenn Sie sich um die Leistung kümmern und die Auswertung des zweiten Operanden keine Nebenwirkungen hervorruft (oder wenn Sie sich nicht um sie kümmern), verwenden Sie auf jeden Fall den Kurzschlussoperator . Wenn Sie jedoch aus irgendeinem Grund die Nebenwirkungen des zweiten Operanden benötigen , sollten Sie den Operator ohne Kurzschluss verwenden.

Ein Beispiel, bei dem Sie den Nicht-Kurzschlussoperator verwenden sollten:

if( write_customer_to_database() != SUCCESS |
    write_supplier_to_database() != SUCCESS |
    write_order_to_database() != SUCCESS )
{
    transaction_rollback();
}

(*) Mit Ausnahme eines wirklich perversen Szenarios, in dem die Bewertung des ersten Operanden auf falsch durch Nebenwirkung den zweiten Operanden auf wahr anstatt auf falsch bewertet.

Mike Nakis
quelle
2
+1 Aber ich möchte hinzufügen, dass neben der Verwendung von Funktionen zur Anzeige von Erfolg oder Misserfolg (wie in Ihrem Beispiel): Funktionen mit Nebenwirkungen sollten generell vermieden werden ...
Marjan Venema
1
Ja, das ist wahrscheinlich der Grund, warum ich bis heute noch keinen der Nicht-Kurzschlussbetreiber verwendet habe, und die Chancen stehen schlecht, dass ich es jemals tun werde.
Mike Nakis
Dieses Beispiel hängt davon ab, welche Operanden in strikter Reihenfolge von links nach rechts ausgewertet werden. C # garantiert dies, viele ähnliche Sprachen (einschließlich C und C ++) jedoch nicht.
Keith Thompson
Wäre eine Kurzschlussbewertung für dieses Beispiel nicht sinnvoll, da alle Transaktionen zurückgesetzt werden, wenn eine von ihnen fehlschlägt? (Ich mache einige Annahmen über die Semantik der Anrufe.)
Keith Thompson
@KeithThompson Sie haben Recht, eine Bewertung ohne Kurzschluss führt zu unnötiger Verarbeitung, und in diesem Sinne ist das Beispiel etwas lahm, aber es ist nicht so lahm, dass eine Änderung gerechtfertigt ist, da die Wahrheit bei einer Kurzschlussbewertung bleibt, wenn write_customer_to_database () ist erfolgreich, dann werden die restlichen write _...-Funktionen niemals aufgerufen, und es ist besser, im Erfolgsfall korrekt zu arbeiten, als im Fehlerfall einige unnötige Operationen auszuführen.
Mike Nakis
4

Es gibt zwei Gründe, die Variante ohne Kurzschluss zu verwenden:

  1. Beibehalten von Nebenwirkungen (aber das ist klarer mit einer temporären Variablen zu codieren)

  2. vereiteln Timing - Attacken durch die Gabel in dem Kurzschluss zu vermeiden (dies kann auch die Laufzeiteffizienz verbessern , wenn der zweite Operand ist eine Variable , aber das ist eine Mikro-Optimierung der Compiler ohnehin machen können)

Ratschenfreak
quelle
Dies ist der einzig richtige Grund, ich habe keine Ahnung, warum dies nicht die akzeptierte Antwort mit den höchsten Stimmen ist ...
Behrooz
2

wenn die rechte Klausel des Bedieners Nebenwirkungen hat und der Programmierer beabsichtigte, dass beide Nebenwirkungen auftreten sollen, bevor der Rückgabewert überprüft wird.

Lie Ryan
quelle
5
Eek. Bitte codieren Sie nicht so… Wenn Sie sich auf Nebenwirkungen verlassen, haben Sie zwei verschiedene Ausdrücke, weisen Sie die Ergebnisse zu und testen Sie sie anschließend .
Konrad Rudolph