Erfordert der ANSI-Standard , dass die logischen Operatoren in C oder C ++ kurzgeschlossen werden?
Ich bin verwirrt, weil ich mich an das K & R-Buch erinnere, in dem es heißt, Ihr Code sollte nicht davon abhängen, dass diese Vorgänge kurzgeschlossen werden, da dies möglicherweise nicht der Fall ist. Könnte jemand bitte darauf hinweisen, wo im Standard gesagt wird, dass logische Operationen immer kurzgeschlossen sind? Ich interessiere mich hauptsächlich für C ++, eine Antwort auch für C wäre toll.
Ich erinnere mich auch daran, dass ich gelesen habe (ich kann mich nicht erinnern, wo), dass die Auswertungsreihenfolge nicht streng definiert ist, sodass Ihr Code nicht davon abhängen oder annehmen sollte, dass Funktionen innerhalb eines Ausdrucks in einer bestimmten Reihenfolge ausgeführt werden: Am Ende einer Anweisung werden alle Funktionen, auf die verwiesen wird wird aufgerufen worden sein, aber der Compiler hat die Freiheit, die effizienteste Reihenfolge auszuwählen.
Gibt der Standard die Bewertungsreihenfolge dieses Ausdrucks an?
if( functionA() && functionB() && functionC() ) cout<<"Hello world";
quelle
Antworten:
Ja, für Bediener
||
und&&
sowohl in C- als auch in C ++ - Standards sind Kurzschluss- und Auswertungsreihenfolge erforderlich .Der C ++ - Standard sagt (es sollte eine äquivalente Klausel im C-Standard geben):
In C ++ gibt es eine zusätzliche Falle: Kurzschluss gilt NICHT für Typen, die Operatoren
||
und überladen&&
.Es wird normalerweise nicht empfohlen, diese Operatoren in C ++ zu überladen, es sei denn, Sie haben eine ganz bestimmte Anforderung. Sie können dies tun, es kann jedoch das erwartete Verhalten im Code anderer Personen beeinträchtigen, insbesondere wenn diese Operatoren indirekt über das Instanziieren von Vorlagen verwendet werden, wobei der Typ diese Operatoren überlastet.
quelle
Die Kurzschlussbewertung und die Reihenfolge der Bewertung ist sowohl in C als auch in C ++ ein vorgeschriebener semantischer Standard.
Wenn dies nicht der Fall wäre, wäre Code wie dieser keine gängige Redewendung
In Abschnitt 6.5.13 Logischer UND-Operator der C99-Spezifikation (PDF-Link) heißt es
In ähnlicher Weise Abschnitt 6.5.14 Logical OR - Operator sagt
Ein ähnlicher Wortlaut findet sich in den C ++ - Standards, siehe Abschnitt 5.14 in diesem Entwurf . Wie Prüfer in einer anderen Antwort feststellt, müssen beide Operanden ausgewertet werden, wenn Sie && oder || überschreiben, da dies zu einem regulären Funktionsaufruf wird.
quelle
Ja, das ist vorgeschrieben (sowohl Bewertungsreihenfolge als auch Kurzschluss). Wenn in Ihrem Beispiel alle Funktionen true zurückgeben, ist die Reihenfolge der Aufrufe streng von FunktionA, dann von FunktionB und dann von FunktionC. Wird dafür gerne verwendet
Gleiches gilt für den Komma-Operator:
Man sagt , zwischen den linken und rechten Operanden
&&
,||
,,
und zwischen den ersten und den zweiten / dritten Operanden?:
(Bedingungsoperator) ist ein „Sequenzpunkt“. Alle Nebenwirkungen werden vor diesem Zeitpunkt vollständig bewertet. Das ist also sicher:Beachten Sie, dass der Kommaoperator nicht mit dem syntaktischen Komma verwechselt werden darf, mit dem Dinge getrennt werden:
Der C ++ Standard sagt in
5.14/1
:Und in
5.15/1
:Es heißt für beide neben denen:
Darüber hinaus
1.9/18
sagtquelle
Direkt vom guten alten K & R:
quelle
Sei sehr sehr vorsichtig.
Für grundlegende Typen sind dies Verknüpfungsoperatoren.
Wenn Sie diese Operatoren jedoch für Ihre eigenen Klassen- oder Aufzählungstypen definieren, handelt es sich nicht um Verknüpfungen. Aufgrund dieses semantischen Unterschieds in ihrer Verwendung unter diesen verschiedenen Umständen wird empfohlen, diese Operatoren nicht zu definieren.
Für die
operator &&
undoperator ||
für Grundtypen ist die Bewertungsreihenfolge von links nach rechts (andernfalls wäre eine Abkürzung schwierig :-) Für überladene Operatoren, die Sie definieren, handelt es sich im Grunde genommen um syntaktischen Zucker zur Definition einer Methode, und daher ist die Reihenfolge der Bewertung der Parameter nicht definiert.quelle
Ihre Frage hängt von der Priorität und Assoziativität des C ++ - Operators ab . Grundsätzlich erstellt der Compiler in Ausdrücken mit mehreren Operatoren und ohne Klammern den Ausdrucksbaum, indem er diese Regeln befolgt.
Wenn Sie so etwas haben
A op1 B op2 C
, können Sie die Dinge vorrangig entweder(A op1 B) op2 C
oder gruppierenA op1 (B op2 C)
. Wenn esop1
eine höhere Priorität als hatop2
, erhalten Sie den ersten Ausdruck. Andernfalls erhalten Sie den zweiten.Aus
A op B op C
Gründen der Assoziativität können Sie, wenn Sie so etwas haben , die Ausdünnungen erneut als(A op B) op C
oder gruppierenA op (B op C)
. Wennop
die Assoziativität verlassen wurde, erhalten wir den ersten Ausdruck. Wenn es die richtige Assoziativität hat, erhalten wir die zweite. Dies funktioniert auch für Bediener mit derselben Prioritätsebene.In diesem speziellen Fall
&&
hat eine höhere Priorität als||
, sodass der Ausdruck als ausgewertet wird(a != "" && it == seqMap.end()) || isEven
.Die Reihenfolge selbst ist in der Ausdrucksbaumform "von links nach rechts". Also werden wir zuerst bewerten
a != "" && it == seqMap.end()
. Wenn es wahr ist, ist der ganze Ausdruck wahr, sonst gehen wir zuisEven
. Die Prozedur wiederholt sich natürlich rekursiv innerhalb des linken Unterausdrucks.Interessante Leckerbissen, aber das Konzept der Vorrangstellung hat seine Wurzeln in der mathematischen Notation. Das gleiche passiert in
a*b + c
, wo*
hat höhere Priorität als+
.Noch interessanter / dunkler ist, dass für einen nicht parenthasierten Ausdruck
A1 op1 A2 op2 ... opn-1 An
, bei dem alle Operatoren dieselbe Priorität haben, die Anzahl der binären Ausdrucksbäume, die wir bilden könnten, durch die sogenannten katalanischen Zahlen angegeben wird . Für großen
wachsen diese extrem schnell. dquelle
Wenn Sie Wikipedia vertrauen:
C (Programmiersprache)
quelle