In C-Sprache, Why does n++
schneller ausführen als n=n+1
?
(int n=...; n++;)
(int n=...; n=n+1;)
Unsere Lehrerin hat diese Frage in der heutigen Klasse gestellt. (Das ist keine Hausaufgabe)
In C-Sprache, Why does n++
schneller ausführen als n=n+1
?
(int n=...; n++;)
(int n=...; n=n+1;)
Unsere Lehrerin hat diese Frage in der heutigen Klasse gestellt. (Das ist keine Hausaufgabe)
Betamoo
Das wäre wahr, wenn Sie an einem arbeiten “Steinzeit” Compiler…
Im Falle von “Steinzeit”:
++n
ist schneller als n++
ist schneller als n=n+1
Maschine haben normalerweise increment x
ebenso gut wie add const to x
n++
Sie haben nur 2 Speicherzugriffe (lesen n, inc n, schreiben n )n=n+1
Sie haben 3 Speicherzugriffe (lesen n, lesen const, addieren n und const, schreiben n)Aber der heutige Compiler konvertiert automatisch n=n+1
zu ++n
und es wird mehr tun, als Sie sich vorstellen können !!
Auch auf den heutigen Out-of-Order-Prozessoren – trotz des Falls von “Steinzeit” Compiler-Laufzeit darf nicht beeinträchtigt werden überhaupt in vielen Fällen!!
Verwandt
@gcc: Nein, das solltest du NICHT sagen. Sie sollten sagen: “Es sollte überhaupt keinen Unterschied zwischen den beiden geben. Optimierende Compiler haben solche Dinge seit Jahrzehnten gehandhabt, seit zumindest der Bliss-11-Compiler, der in “Design of an Optimizing Compiler” von Wulf et al. beschrieben wird.”
– John R. Strohm
21. Mai 2010 um 19:14 Uhr
Auf dem Computer habe ich davon erfahren, ++n
und n++
waren genau die gleiche Geschwindigkeit, es musste kein Laden-Inkrement-Speichern durchgeführt werden, und der einzige Geschwindigkeitsunterschied, den Sie sehen würden, hing davon ab, ob n
in einem Register oder Speicher gespeichert wurde (nicht ob n gerade in einem Register war, sondern ob der zugewiesene Speicher in einem Register war oder nicht) zB move (n)+,r0
verschiebt n zum Register Null und inkrementiert n nach der Verschiebung. (VAX-11-Montage)
– Stefan P
21. Mai 2010 um 19:33 Uhr
+1, um die Frage tatsächlich auf nützliche Weise zu beantworten, anstatt nur zu sagen, dass sie gleich sind, was nützlich zu wissen ist, aber nicht die Informationen, die das OP wahrscheinlich wollte.
– Ben Zotto
21. Mai 2010 um 20:11 Uhr
Zu sagen, der Compiler wird “konvertieren n=n+1
zu ++n
“ ist einfach falsch oder sogar Unsinn. Es ist, als würde man sagen, dass ein Übersetzer „konvertieren wird it is
zu it's
” beim Übersetzen aus dem Englischen ins Französische. Die Unterscheidung zwischen den beiden ist ein Artefakt des Ausgangssprache.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
17. Dezember 2010 um 20:14 Uhr
Mir wurde beigebracht. ++n ist zwar schneller, aber niemals langsamer als n++. Für jede beliebige Hardware.
– EnabrenTane
23. Dezember 2010 um 5:41 Uhr
Auf GCC 4.4.3 für x86 mit oder ohne Optimierungen kompilieren sie zu genau demselben Assemblercode und benötigen daher dieselbe Zeit für die Ausführung. Wie Sie in der Assembly sehen können, konvertiert GCC einfach n++
hinein n=n+1
optimiert es dann in die Ein-Anweisung add (in -O2).
Der Vorschlag deines Lehrers n++
ist schneller gilt nur für sehr alte, nicht optimierende Compiler, die nicht schlau genug waren, die In-Place-Update-Anweisungen für auszuwählen n = n + 1
. Diese Compiler sind in der PC-Welt seit Jahren veraltet, können aber immer noch für seltsame proprietäre eingebettete Plattformen gefunden werden.
C-Code:
int n;
void nplusplus() {
n++;
}
void nplusone() {
n = n + 1;
}
Ausgabeassembly (keine Optimierungen):
.file "test.c"
.comm n,4,4
.text
.globl nplusplus
.type nplusplus, @function
nplusplus:
pushl %ebp
movl %esp, %ebp
movl n, %eax
addl $1, %eax
movl %eax, n
popl %ebp
ret
.size nplusplus, .-nplusplus
.globl nplusone
.type nplusone, @function
nplusone:
pushl %ebp
movl %esp, %ebp
movl n, %eax
addl $1, %eax
movl %eax, n
popl %ebp
ret
.size nplusone, .-nplusone
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Ausgangsassembly (mit -O2-Optimierungen):
.file "test.c"
.text
.p2align 4,,15
.globl nplusplus
.type nplusplus, @function
nplusplus:
pushl %ebp
movl %esp, %ebp
addl $1, n
popl %ebp
ret
.size nplusplus, .-nplusplus
.p2align 4,,15
.globl nplusone
.type nplusone, @function
nplusone:
pushl %ebp
movl %esp, %ebp
addl $1, n
popl %ebp
ret
.size nplusone, .-nplusone
.comm n,4,4
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Der Compiler optimiert n + 1
ins Nichts.
Meinst du n = n + 1
?
Wenn dies der Fall ist, werden sie zu einer identischen Assembly kompiliert. (Angenommen, die Optimierungen sind aktiviert und es handelt sich um Anweisungen, nicht um Ausdrücke.)
Wer sagt, dass es das tut? Ihr Compiler optimiert alles weg, wirklich, was es zu einem strittigen Punkt macht.
Moderne Compiler sollten in der Lage sein, beide Formen als gleichwertig zu erkennen und sie in das Format zu konvertieren, das auf Ihrer Zielplattform am besten funktioniert. Es gibt eine Ausnahme von dieser Regel: Variablenzugriffe, die Seiteneffekte haben. Zum Beispiel, wenn n
ein speicherabgebildetes Hardwareregister ist, kann das Lesen und Schreiben darauf mehr bewirken, als nur einen Datenwert zu übertragen (Lesen kann beispielsweise einen Interrupt löschen). Sie würden die verwenden volatile
Schlüsselwort, um den Compiler wissen zu lassen, dass er bei der Optimierung des Zugriffs auf vorsichtig sein muss n
und in diesem Fall generiert der Compiler möglicherweise einen anderen Code von n++
(Inkrementoperation) und n = n + 1
(Lesen, Hinzufügen und Speichern von Vorgängen). Für normale Variablen sollte der Compiler jedoch beide Formen auf dasselbe optimieren.
Diese Antwort ist falsch. volatile
ergibt keinen Unterschied zwischen ++n
und n=n+1
. Beide führen zu einem einzelnen Lese- und einem einzelnen Schreibvorgang, und keiner ist atomar. Wenn Sie Atomarität wollen, volatile
kann es nicht liefern; warten auf _Atomic
tippt C1x ein.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
20. Dezember 2010 um 17:19 Uhr
@R: Ich habe nie behauptet, dass “flüchtig” Atomarität liefert. Der Rest Ihres Kommentars ist im allgemeinen Fall nicht wahr (sparen Sie sich den letzten Satz); Die Details, wie ein Compiler Code optimiert, sind implementierungsspezifisch. Meine Antwort erklärt lediglich, wie sich die Verwendung von „volatile“ auf die Compiler-Optimierung im Allgemeinen auswirken kann.
– bta
21. Dezember 2010 um 2:01 Uhr
@R..GitHubSTOPHELPINGICE: Der Standard verlangt das nicht volatile
Bereitstellung von Atomizität, aber wenn eine Plattform in der Lage ist, einige atomare Operationen an Hardwareregistern durchzuführen, ohne alle diejenigen zu unterstützen, die zur Unterstützung von C11-Atomfunktionen verpflichtet sind, dokumentieren Sie, dass sie einige Konstrukte implementiert, die beteiligt sind volatile
in atomarer Form scheint der praktischste Weg zu sein, eine solche Unterstützung bereitzustellen. Weitaus besser als atomare Typen, die alle Operationen in fehlerhafter Weise implementieren müssen und keine in der nützlichen Weise implementieren können, die von Hardware unterstützt wird.
– Superkatze
9. November 2021 um 7:36 Uhr
Welpe
Es tut nicht wirklich. Der Compiler nimmt Änderungen vor, die für die Zielarchitektur spezifisch sind. Mikrooptimierungen wie diese haben oft zweifelhafte Vorteile, sind aber vor allem die Zeit des Programmierers sicherlich nicht wert.
Diese Antwort ist falsch. volatile
ergibt keinen Unterschied zwischen ++n
und n=n+1
. Beide führen zu einem einzelnen Lese- und einem einzelnen Schreibvorgang, und keiner ist atomar. Wenn Sie Atomarität wollen, volatile
kann es nicht liefern; warten auf _Atomic
tippt C1x ein.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
20. Dezember 2010 um 17:19 Uhr
@R: Ich habe nie behauptet, dass “flüchtig” Atomarität liefert. Der Rest Ihres Kommentars ist im allgemeinen Fall nicht wahr (sparen Sie sich den letzten Satz); Die Details, wie ein Compiler Code optimiert, sind implementierungsspezifisch. Meine Antwort erklärt lediglich, wie sich die Verwendung von „volatile“ auf die Compiler-Optimierung im Allgemeinen auswirken kann.
– bta
21. Dezember 2010 um 2:01 Uhr
@R..GitHubSTOPHELPINGICE: Der Standard verlangt das nicht volatile
Bereitstellung von Atomizität, aber wenn eine Plattform in der Lage ist, einige atomare Operationen an Hardwareregistern durchzuführen, ohne alle diejenigen zu unterstützen, die zur Unterstützung von C11-Atomfunktionen verpflichtet sind, dokumentieren Sie, dass sie einige Konstrukte implementiert, die beteiligt sind volatile
in atomarer Form scheint der praktischste Weg zu sein, eine solche Unterstützung bereitzustellen. Weitaus besser als atomare Typen, die alle Operationen in fehlerhafter Weise implementieren müssen und keine in der nützlichen Weise implementieren können, die von Hardware unterstützt wird.
– Superkatze
9. November 2021 um 7:36 Uhr
Weizen
Tatsächlich liegt der Grund darin, dass der Operator für Postfix anders definiert ist als für Präfix. ++n
wird “n” erhöhen und einen Verweis auf “n” zurückgeben, während n++
wird “n” erhöhen wird a zurückgeben const
Kopie von “n”. Daher der Satz n = n + 1
wird effizienter sein. Aber ich muss den obigen Postern zustimmen. Gute Compiler sollten ein ungenutztes Rückgabeobjekt wegoptimieren.
@R und mehr zu dem Punkt, wenn man sich den Verlauf ansieht, wurde er erstaunliche 13 Mal bearbeitet, komplett mit Titeländerung, Tag-Änderungen und Fragenänderungen. Mich niederzuschreiben, ohne den historischen Kontext zu nehmen, ist ziemlich schlecht. Normalerweise wäre ich nicht so hochmütig, aber bedeutet das, dass ich alle meine Antworten durchgehen muss, um sicherzustellen, dass die Frage nicht so weit bearbeitet wurde, dass ich einige Monate später heruntergestimmt werden könnte?
– Weizen
20. September 2010 um 4:06 Uhr
Entschuldigung, war mir nicht bewusst. Ich würde die -1 entfernen, wenn ich könnte.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
17. Dezember 2010 um 20:16 Uhr
@R Warum kannst du die -1 nicht entfernen?
– Ergwun
22. Dezember 2010 um 0:49 Uhr
Nach einer gewissen Zeit können Sie Ihre Bewertung nur noch ändern, wenn die Antwort bearbeitet wird.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
23. Dezember 2010 um 23:55 Uhr
Wie hast du das herausgefunden? Auf welchem Compiler/Betriebssystem/Plattform/Architektur?
– mmx
21. Mai 2010 um 18:59 Uhr
Im Allgemeinen nicht. Sie können keine sinnvolle Aussage machen, dass “
a
ist schneller alsb
” (woa
undb
sind C-Ausdrücke). Es macht nur Sinn zu sagen, dass “a
ist schneller alsb
auf Hardwarec
wenn mit Version kompiliertd
des Compilerse
mit Optimierungsflagsf
” (und ein paar andere Anforderungen auch).– Stefan Kanon
21. Mai 2010 um 19:04 Uhr
Aus dem Beispiel geht hervor, was hier gefragt wird; Nur weil die Antwort offensichtlich erscheint, heißt das nicht, dass Sie sie schließen sollten. +1 für Wiedereröffnung.
– bdonlan
21. Mai 2010 um 19:15 Uhr
@Stephen: Der Fragesteller sollte also in der Antwort korrigiert werden. Es ist immer noch eine gute Frage, weil jemand anderes später auf die gleiche Fehlinformation stoßen könnte, und diese Frage wird helfen, sie zu sortieren
– bdonlan
21. Mai 2010 um 19:22 Uhr
@Stephen, auch wenn Sie wirklich der Meinung sind, dass die Frage keine falsche Aussage stellen sollte, können Sie sie gerne in “Ist
n++
schneller alsn = n + 1
und warum?”. Das ist viel konstruktiver, als es einfach ohne Diskussion zu schließen 🙂– bdonlan
21. Mai 2010 um 19:23 Uhr