2012-09-22 8 views
9

Die Norm legt nicht die Reihenfolge der Auswertung der Argumente mit dieser Zeile:Warum ist die Reihenfolge der Auswertung für Funktionsparameter in C++ nicht angegeben?

Die Reihenfolge der Auswertung der Argumente nicht spezifiziert ist.

Was bedeutet

Bessere Code kann in Abwesenheit von Beschränkungen Ausdruck Auswerteauftrag

implizieren erzeugt werden?

Was ist der Nachteil, wenn man alle Compiler auffordert, die Funktionsargumente von links nach rechts zu bewerten? Welche Arten von Optimierungen führen Compiler aufgrund dieser nicht spezifizierten Spezifikation durch?

+4

Wenn dem Compiler ermöglicht wird, die Auswertung der Operanden neu zu ordnen, wird mehr Platz für die Optimierung geboten. – Mysticial

+1

@Mysticial: Absurd wie es aussehen könnte, sollte das eine Antwort sein, und eigentlich die * angenommene * Antwort! –

+0

Welche Arten von Optimierungen führen die Compiler durch? – unj2

Antwort

25

Indem dem Compiler ermöglicht wird, die Auswertung der Operanden neu zu ordnen, wird mehr Platz für die Optimierung geboten.

Hier ist ein vollständig aufgebautes Beispiel für Illustrationszwecke.

Angenommen, der Prozessor kann:

  • Issue 1 Anweisung in jedem Zyklus.
  • Eine Addition in 1 Zyklus ausführen.
  • Führen Sie eine Multiplikation in 3 Zyklen durch.
  • Kann Additionen und Multiplikationen zur gleichen Zeit ausführen.

Angenommen, Sie einen Funktionsaufruf haben wie folgt:

foo(a += 1, b += 2, c += 3, d *= 10); 

Wenn Sie auf einem Prozessor ohne OOE diese von links nach rechts auszuführen waren:

Cycle - Operation 
0  - a += 1 
1  - b += 2 
2  - c += 3 
3  - d *= 10 
4  - d *= 10 
5  - d *= 10 

Nun, wenn Sie Erlauben Sie dem Compiler, sie neu zu ordnen: (und starten Sie zuerst die Multiplikation)

Cycle - Operation 
0  - d *= 10 
1  - a += 1, d *= 10 
2  - b += 2, d *= 10 
3  - c += 3 

Also 6 Zyklen vs. 4 Zyklen.

Wieder ist dies völlig erfunden. Moderne Prozessoren sind viel komplizierter als das. Aber du hast die Idee.

1

Hier ist ein einfaches Beispiel. Angenommen, Sie einen Funktionsaufruf haben wie folgt:

// assume that p is a pointer to an integer 
foo(*p * 3, bar(), *p * 3 + 1); 

Der Compiler zu dereferenzieren muss p zweimal (und einige Berechnungen tun auf der Grundlage des Ergebnisses) und rufen bar einmal. Wenn der Compiler klug ist, könnte es um die Auswertung zu

int temp = *p * 3; 
foo(temp, bar(), temp + 1); 

Auf diese Weise hat sie neu ordnet den „dereferenzieren, multipliziert mit 3“ zu tun, nur einmal. Dies ist als allgemeine Teilausdruck-Eliminierung bekannt.

+1

Um fair zu sein, können sogar Sprachen, die die Reihenfolge der Auswertung garantieren, dies tun, vorausgesetzt, sie können nachweisen, dass sich der Wert von "p" dazwischen nicht ändern kann. Natürlich ist das mit dem C-Speichermodell ziemlich unmöglich zu garantieren, weshalb wahrscheinlich eine undefinierte Reihenfolge der Auswertung notwendig ist, um diese Optimierung zu erreichen. – Joey