532 Stimmen

Gibt es einen Leistungsunterschied zwischen i++ und ++i in C?

Gibt es einen Leistungsunterschied zwischen i++ y ++i wenn der resultierende Wert nicht verwendet wird?

462voto

Mark Harrison Punkte 281807

Zusammenfassung: Nein.

i++ könnte möglicherweise langsamer sein als ++i , da der alte Wert von i für eine spätere Verwendung gespeichert werden müssen, aber in der Praxis sind alle modernen Compiler dies wegoptimieren.

Wir können dies anhand des Codes für diese Funktion demonstrieren, sowohl mit ++i y i++ .

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

Die Dateien sind identisch, mit Ausnahme von ++i y i++ :

$ diff i++.c ++i.c
6c6
<     for (i = 0; i < 100; i++)
---
>     for (i = 0; i < 100; ++i)

Wir werden sie kompilieren und auch den erzeugten Assembler erhalten:

$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c

Und wir können sehen, dass sowohl die erzeugten Objekt- als auch die Assemblerdateien identisch sind.

$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e

$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22

132voto

Desde Effizienz versus Absicht von Andrew Koenig :

Erstens ist es alles andere als offensichtlich, dass ++i ist effizienter als i++ zumindest wenn es sich um ganzzahlige Variablen handelt.

Und :

Die Frage, die man sich stellen sollte, ist also nicht, welche der beiden Operationen schneller ist, sondern welche der beiden Operationen das, was man erreichen will, genauer ausdrückt. Ich behaupte, wenn Sie den Wert des Ausdrucks nicht verwenden, gibt es keinen Grund, die Operation i++ anstelle von ++i denn es gibt nie einen Grund, den Wert einer Variablen zu kopieren, die Variable zu erhöhen und die Kopie dann wegzuwerfen.

Wenn also der resultierende Wert nicht verwendet wird, würde ich ++i . Aber nicht, weil es effizienter ist, sondern weil es meine Absicht korrekt wiedergibt.

54voto

Andrew Grant Punkte 57342

Eine bessere Antwort ist, dass ++i wird manchmal schneller, aber nie langsamer sein.

Jeder scheint davon auszugehen, dass i ist ein regulärer eingebauter Typ wie int . In diesem Fall wird es keinen messbaren Unterschied geben.

Wenn jedoch i komplexer Art ist, können Sie durchaus einen messbaren Unterschied feststellen. Für i++ müssen Sie eine Kopie Ihrer Klasse erstellen, bevor Sie sie inkrementieren. Je nachdem, was in einer Kopie enthalten ist, könnte es tatsächlich langsamer sein, da mit ++i können Sie einfach den Endwert zurückgeben.

Foo Foo::operator++()
{
  Foo oldFoo = *this; // copy existing value - could be slow
  // yadda yadda, do increment
  return oldFoo;
}

Ein weiterer Unterschied besteht darin, dass bei ++i haben Sie die Möglichkeit, einen Verweis anstelle eines Wertes zurückzugeben. Je nachdem, was mit der Erstellung einer Kopie Ihres Objekts verbunden ist, könnte dies wiederum langsamer sein.

Ein Beispiel aus der Praxis, wo dies vorkommen kann, ist die Verwendung von Iteratoren. Es ist unwahrscheinlich, dass das Kopieren eines Iterators ein Flaschenhals in Ihrer Anwendung ist, aber es ist trotzdem eine gute Praxis, sich die Verwendung von ++i anstelle von i++ wo das Ergebnis nicht beeinflusst wird.

24voto

Lundin Punkte 171916

Kurze Antwort:

Es besteht niemals ein Unterschied zwischen i++ y ++i in Bezug auf die Geschwindigkeit. Ein guter Compiler sollte in beiden Fällen keinen unterschiedlichen Code erzeugen.

Lange Antwort:

Was alle anderen Antworten verschweigen, ist, dass der Unterschied zwischen ++i gegen i++ ist nur innerhalb des Ausdrucks sinnvoll, in dem er vorkommt.

Im Fall von for(i=0; i<n; i++) die i++ ist allein in seinem eigenen Ausdruck: Es gibt einen Sequenzpunkt vor der i++ und es gibt noch einen danach. Der einzige erzeugte Maschinencode ist also "increase i von 1 "und es ist klar definiert, wie dies in Bezug auf den Rest des Programms abläuft. Wenn Sie es also ändern würden in Präfix ++ wäre das völlig egal, Sie würden immer noch den Maschinencode "increase" erhalten. i von 1 ".

Die Unterschiede zwischen ++i y i++ ist nur bei Ausdrücken wie array[i++] = x; gegen array[++i] = x; . Einige mögen einwenden, dass das Postfix bei solchen Operationen langsamer ist, weil das Register, in dem i Residenzen müssen später nachgeladen werden. Beachten Sie jedoch, dass der Compiler die Anweisungen beliebig anordnen kann, solange dies nicht "das Verhalten der abstrakten Maschine beeinträchtigt", wie es im C-Standard heißt.

Sie können also davon ausgehen, dass array[i++] = x; wird in Maschinencode übersetzt als:

  • Wert von speichern i im Register A.
  • Adresse des Arrays in Register B speichern.
  • Addiere A und B, speichere das Ergebnis in A.
  • An dieser neuen Adresse, die durch A repräsentiert wird, speichern Sie den Wert von x.
  • Wert von speichern i in Register A // ineffizient, weil zusätzliche Anweisung hier, wir haben das schon einmal gemacht.
  • Register A inkrementieren.
  • Register A speichern in i .

könnte der Compiler den Code auch effizienter erstellen, z. B.:

  • Wert von speichern i im Register A.
  • Adresse des Arrays in Register B speichern.
  • Addiere A und B, speichere das Ergebnis in B.
  • Register A inkrementieren.
  • Register A speichern in i .
  • ... // Rest des Codes.

Nur weil Sie als C-Programmierer darauf trainiert sind zu denken, dass das Postfix ++ am Ende passiert, muss der Maschinencode nicht auf diese Weise geordnet werden.

Es gibt also keinen Unterschied zwischen Präfix und Postfix ++ in C. Sie als C-Programmierer sollten sich jedoch vor Leuten hüten, die in einigen Fällen inkonsequenterweise Präfix und in anderen Fällen Postfix verwenden, ohne dafür eine Begründung zu haben. Das deutet darauf hin, dass sie unsicher sind, wie C funktioniert, oder dass sie die Sprache nicht richtig beherrschen. Das ist immer ein schlechtes Zeichen, denn es deutet wiederum darauf hin, dass sie andere fragwürdige Entscheidungen in ihrem Programm treffen, die auf Aberglauben oder "religiösen Dogmen" beruhen.

"Vorwahl ++ ist immer schneller" ist in der Tat ein solches falsches Dogma, das unter angehenden C-Programmierern weit verbreitet ist.

20voto

Zuallererst: Der Unterschied zwischen i++ y ++i ist in C vernachlässigbar.


Zu den Details.

1. Das wohlbekannte C++-Problem: ++i ist schneller

In C++, ++i effizienter ist, wenn i ist eine Art Objekt mit einem überladenen Inkrement-Operator.

Warum?
En ++i wird das Objekt zunächst inkrementiert und kann anschließend als konstante Referenz an jede andere Funktion übergeben werden. Dies ist nicht möglich, wenn der Ausdruck foo(i++) denn jetzt muss das Inkrement erfolgen, bevor foo() aufgerufen wird, aber der alte Wert muss an foo() . Folglich ist der Compiler gezwungen, eine Kopie von i bevor es den Inkrement-Operator auf dem Original ausführt. Die zusätzlichen Konstruktor-/Destruktoraufrufe sind der schlechte Teil.

Wie bereits erwähnt, gilt dies nicht für Grundtypen.

2. Die wenig bekannte Tatsache: i++ Mai schneller sein

Wenn kein Konstruktor/Destruktor aufgerufen werden muss, was in C immer der Fall ist, ++i y i++ sollte doch gleich schnell sein, oder? Nein. Sie sind praktisch gleich schnell, aber es kann kleine Unterschiede geben, die die meisten anderen Antwortenden falsch verstanden haben.

Wie können i++ schneller sein?
Es geht um die Datenabhängigkeit. Wenn der Wert aus dem Speicher geladen werden muss, müssen zwei aufeinander folgende Operationen mit ihm durchgeführt werden, nämlich das Inkrementieren und die Verwendung des Wertes. Mit ++i muss die Inkrementierung durchgeführt werden vor kann der Wert verwendet werden. Mit i++ ist die Verwendung nicht vom Inkrement abhängig, und die CPU kann den Verwendungsvorgang durchführen parallel dazu auf die Inkrementierungsoperation. Der Unterschied beträgt höchstens einen CPU-Zyklus, ist also wirklich vernachlässigbar, aber er ist da. Und es ist andersherum, als viele erwarten würden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X