C oder C ++: for-Schleifenvariable

8

Meine Frage ist sehr einfach. In C oder C ++:

Nehmen wir an, die for -Schleife ist wie folgt,

%Vor%

Meine Frage ist, ob die Berechnung a+b für jede for -Schleife durchgeführt wird oder ob sie nur einmal am Anfang der Schleife berechnet wird?

Für meine Anforderungen ist der Wert a+b konstant. Wenn a+b berechnet wird und auf den Wert someArray[a+b] jedes Mal in der Schleife zugegriffen wird, würde ich eine temporäre Variable für someArray[a+b] verwenden, um eine bessere Leistung zu erzielen.

    
Sathish Krishnan 13.11.2013, 14:21
quelle

12 Antworten

7

Sie können herausfinden, wenn Sie sich den generierten Code ansehen

%Vor%

und

%Vor%

Sehen Sie sich die Ausgabe file.s an und vergleichen Sie die beiden Versionen. Wenn someArray[a+b] für alle Schleifenzyklen auf einen konstanten Wert reduziert werden kann, wird dies normalerweise vom Optimierer durchgeführt und in eine temporäre Variable oder ein Register übernommen.

    
Olaf Dietsche 13.11.2013, 14:25
quelle
4

Es verhält sich als ob es jedes Mal berechnet wurde. Wenn der Compiler optimiert und in der Lage ist nachzuweisen, dass sich das Ergebnis nicht ändert, darf die Berechnung aus der Schleife entfernt werden. Andernfalls wird es jedes Mal neu berechnet.

Wenn Sie sicher sind, dass das Ergebnis konstant ist und die Geschwindigkeit wichtig ist, verwenden Sie eine Variable zum Zwischenspeichern.

    
Angew 13.11.2013 14:25
quelle
3
  

wird für jede for-Schleife ausgeführt oder nur einmal am Anfang der Schleife berechnet?

Wenn der Compiler diesen Code nicht optimiert, wird er jedes Mal berechnet. Sicherer ist es, eine temporäre Variable zu verwenden, die nicht zu viel kosten sollte.

    
Sadique 13.11.2013 14:23
quelle
3

Erstens geben die C- und C ++ - Standards nicht vor, wie eine Implementierung i<someArray[a+b] auswerten soll, nur dass das Ergebnis so aussehen muss, als ob es bei jeder Iteration ausgeführt würde (sofern das Programm anderen Sprachanforderungen entspricht).

Zweitens wird jede C- und C ++ - Implementierung von mäßiger Qualität das Ziel haben, die wiederholte Auswertung von Ausdrücken zu vermeiden, deren Wert sich nicht ändert, sofern die Optimierung nicht deaktiviert ist.

Drittens können verschiedene Dinge dieses Ziel beeinträchtigen, einschließlich:

  • Wenn a , b oder someArray mit außerhalb der Funktion sichtbarem Bereich deklariert sind (z. B. im Dateibereich deklariert sind) und der Code in der Schleife andere Funktionen aufruft, kann dies die C- oder C ++ - Implementierung sein kann nicht feststellen, ob a , b oder someArray während der Schleife geändert wurden.
  • Wenn die Adresse von a , b oder someArray oder ihre Elemente verwendet wird, kann die C- oder C ++ - Implementierung möglicherweise nicht feststellen, ob diese Adresse zum Ändern dieser Objekte verwendet wird. Dies schließt die Möglichkeit ein, dass someArray ein in die Funktion übergebenes Array ist, so dass seine Adresse anderen Entitäten außerhalb der Funktion bekannt ist.
  • Wenn a , b oder die Elemente von someArray volatile sind, muss die C- oder C ++ - Implementierung davon ausgehen, dass sie jederzeit geändert werden können.

Betrachten Sie diesen Code:

%Vor%

In diesem Code kann die C- oder C ++ - Implementierung normalerweise nicht wissen, ob otherArray auf dasselbe Array (oder einen überlappenden Teil) wie someArray zeigt. Daher muss angenommen werden, dass otherArray[i] = something; someArray[a+b] ändern kann.

Beachten Sie, dass ich bezüglich des größeren Ausdrucks someArray[a+b] geantwortet habe und nicht nur den Teil, nach dem Sie gefragt haben, a+b . Wenn Sie nur an a+b interessiert sind, sind natürlich nur die Faktoren relevant, die a und b betreffen.

    
Eric Postpischil 13.11.2013 14:39
quelle
1

Hängt davon ab, wie gut der Compiler ist, welche Optimierungsstufen Sie verwenden und wie a und b deklariert sind.

Zum Beispiel, wenn a und / oder b volatile Qualifier hat, dann muss der Compiler es jedes Mal lesen. In diesem Fall kann der Compiler keine Optimierung mit dem Wert von a+b auswählen. Andernfalls sehen Sie sich den vom Compiler erzeugten Code an, um zu verstehen, was Ihr Compiler macht.

Es gibt kein Standardverhalten, wie dies in C nicht C ++ berechnet wird.

    
P.P. 13.11.2013 14:28
quelle
1

Ich wette, wenn a und b sich nicht über die Schleife ändern, wird es optimiert. Wenn someArray[a+b] nicht berührt wird, wird es außerdem optimiert. Dies ist tatsächlich wichtiger, da fetching Operationen ziemlich teuer sind.

Das ist mit jedem halbwegs ordentlichen Compiler mit den meisten grundlegenden Optimierungen. Ich werde auch so weit gehen zu sagen, dass Leute, die sagen, dass sie immer bewerten, einfach falsch sind. Es ist nicht immer sicher, und es wird höchstwahrscheinlich wann immer möglich optimiert.

    
luk32 13.11.2013 14:28
quelle
1

Die Berechnung wird pro for loop durchgeführt. Obwohl der Optimierer schlau sein und ihn optimieren kann, wäre es besser, wenn Sie so etwas tun würden:

%Vor%     
dasblinkenlight 13.11.2013 14:25
quelle
0

Es berechnet jedes Mal. Verwenden Sie eine Variable:)

    
spacegospod 13.11.2013 14:23
quelle
0

Sie können es kompilieren und den Assembler-Code überprüfen, nur um sicherzustellen,

Aber ich denke, dass die meisten Compiler clever genug sind, um solche Sachen zu optimieren. (Wenn Sie ein Optimierungs-Flag verwenden)

    
cd611 13.11.2013 14:26
quelle
0

Es könnte jedes Mal berechnet werden oder es könnte optimiert werden. Dies hängt davon ab, ob a und b in einem Bereich existieren, in dem der Compiler garantieren kann, dass keine externe Funktion ihre Werte ändern kann. Das heißt, wenn sie sich in einem globalen Kontext befinden, kann der Compiler nicht garantieren, dass eine Funktion, die Sie in der Schleife aufrufen, sie ändert (es sei denn, Sie rufen keine Funktionen auf). Wenn sie sich nur im lokalen Kontext befinden, kann der Compiler versuchen, diese Berechnung zu optimieren.

Das Generieren von optimiertem und nicht optimiertem Assemblercode ist der einfachste Weg, dies zu überprüfen. Am besten ist es jedoch nicht, weil die Kosten für diese Summe so unglaublich günstig sind. Moderne Prozessoren sind sehr, sehr schnell und die Sache, die langsam ist, zieht Daten aus dem RAM in den Cache. Wenn Sie Ihren Code optimieren möchten, profilieren Sie ihn. rate nicht.

    
apmasell 13.11.2013 14:28
quelle
0

Die Berechnung a+b wird bei jeder Iteration der Schleife ausgeführt, und dann wird das Nachschlagen in someArray bei jeder Iteration der Schleife ausgeführt, so dass Sie möglicherweise viel Prozessorzeit durch eine temporäre Variable sparen können Set außerhalb der Schleife, zum Beispiel (wenn das Array ist ein Array von ints sagen):

%Vor%

Sehr vereinfachte Erklärung:

Wenn der Wert an der Array-Position a+b beispielsweise nur 5 wäre, wären das 5 Berechnungen und 5 Nachschlagevorgänge, also 10 Operationen, die durch eine Variable außerhalb der Schleife durch 8 ersetzt würden (5 Zugriffe (1 pro Iteration der Schleife), 1 Berechnung von a+b , 1 Nachschlagen und 1 Zuweisung an die neue Variable) keine so große Einsparung. Wenn Sie jedoch mit größeren Werten arbeiten, zum Beispiel dem Wert im Array bei a+b id 100, würden Sie möglicherweise 100 Berechnungen und 100 Abfragen durchführen, im Gegensatz zu 103 Operationen, wenn Sie eine Variable außerhalb der Schleife haben (100 Zugriffe ( 1 pro Iteration der Schleife, 1 Berechnung von a+b , 1 Nachschlagen und 1 Zuweisung an die neue Variable).

Der Großteil der obigen Angaben hängt jedoch vom Compiler ab: Je nachdem, welche Switches Sie verwenden, welche Optimierungen der Compiler automatisch anwenden kann usw., kann der Code optimiert werden, ohne dass Sie Änderungen an Ihrem Code vornehmen müssen. Am besten ist es, die Vor- und Nachteile jedes Ansatzes speziell für Ihre aktuelle Implementierung abzuwägen, da das, was für eine große Anzahl von Iterationen geeignet sein mag, für eine kleine Anzahl nicht sehr effizient ist, oder Speicher möglicherweise ein Problem ist, das ein diktieren könnte unterschiedlicher Stil zu Ihrem Programm. . . Nun, Sie bekommen die Idee:)

Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen:)

    
GMasucci 13.11.2013 14:39
quelle
0

für den folgenden Code:

%Vor%

Sie erhalten die folgende Assembly:

%Vor%

Wenn Sie die Compiler-Optimierung anwenden, erhalten Sie die folgende Assembly:

%Vor%

Grundsätzlich, in diesem Fall, mit meinem Compiler (MinGW 4.8.0), wird die Schleife "die Berechnung" unabhängig davon, ob Sie die bedingten Variablen innerhalb der Schleife ändern oder nicht (haben keine Assembly dafür gebucht , aber nimm mein Wort dafür, oder noch besser, tu es nicht und zerlege den Code selbst).

Wenn Sie die Optimierung anwenden, macht der Compiler ein wenig Magie und erstellt eine Reihe von Befehlen, die völlig unkenntlich sind.

Wenn Sie nicht möchten, dass Ihre Schleife durch eine Compiler-Aktion (-On) optimiert wird, deklariert eine Variable, der a+b zugewiesen wird, Ihre Assembly um eine oder zwei Anweisungen.

%Vor%

Assembly:

%Vor%

Denken Sie daran, der Assembler-Code, den ich hier gepostet habe, ist nur das relevante Snippet, es gibt ein bisschen mehr, aber es ist nicht relevant, soweit die Frage geht

    
stellarossa 13.11.2013 14:52
quelle

Tags und Links