Ab gcc 9.3 kompilieren mit -std=c++2a, register erzeugt eine Compiler - Warnung, aber es hat immer noch die gewünschte Wirkung und verhält sich identisch zu C ist , registerwenn sie ohne -O1 Kompilieren - Ofast Optimierungen im Hinblick auf diese Antwort. Die Verwendung von clang ++ - 7 verursacht jedoch einen Compilerfehler. Also ja,register Optimierungen machen nur bei der Standardkompilierung ohne Optimierungs -O-Flags einen Unterschied, aber es handelt sich um grundlegende Optimierungen, die der Compiler selbst mit -O1 herausfinden würde.
Der einzige Unterschied besteht darin, dass Sie in C ++ die Adresse der Registervariablen übernehmen dürfen. Dies bedeutet, dass die Optimierung nur erfolgt, wenn Sie nicht die Adresse der Variablen oder ihrer Aliase (um einen Zeiger zu erstellen) oder eine Referenz verwenden davon im Code (nur bei - O0, da eine Referenz hat auch eine Adresse, weil es ein const Zeiger auf dem Stapel ist , der, wie ein Zeiger kann vom Stapel optimiert werden , wenn mit -Ofast kompilieren, außer sie werden nie angezeigt auf dem Stapel mit -Ofast, da sie im Gegensatz zu einem Zeiger nicht erstellt volatileund ihre Adressen nicht verwendet werden können), andernfalls verhält es sich so, als hätten Sie sie nicht verwendetregister , und der Wert wird auf dem Stapel gespeichert.
Bei -O0 besteht ein weiterer Unterschied darin, dass sich const registergcc C und gcc C ++ nicht gleich verhalten. Verhält sich auf gcc C const registerwie folgt register, da Blockbereiche constauf gcc nicht optimiert sind. Bei Clang C gelten registernichts und nur constBlock-Scope-Optimierungen. Auf gcc C registergelten Optimierungen, constim Blockbereich jedoch keine Optimierung. In gcc C ++ werden sowohl Optimierungen registerals auch constBlockbereichsoptimierungen kombiniert.
#include <stdio.h> //yes it's C code on C++
int main(void) {
const register int i = 3;
printf("%d", i);
return 0;
}
int i = 3;::
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
register int i = 3;::
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 8
mov ebx, 3
mov esi, ebx
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
mov rbx, QWORD PTR [rbp-8] //callee restoration
leave
ret
const int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3 //still saves to stack
mov esi, 3 //immediate substitution
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
const register int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov esi, 3 //loads straight into esi saving rbx push/pop and extra indirection (because C++ block-scope const is always substituted immediately into the instruction)
mov edi, OFFSET FLAT:.LC0 // can't optimise away because printf only takes const char*
mov eax, 0 //zeroed: https://stackoverflow.com/a/6212755/7194773
call printf
mov eax, 0 //default return value of main is 0
pop rbp //nothing else pushed to stack -- more efficient than leave (rsp == rbp already)
ret
registerweist den Compiler an, 1) in diesem Fall eine lokale Variable in einem von einem Angerufenen gespeicherten Register zu speichern rbxund 2) Stapelschreibvorgänge zu optimieren, wenn die Adresse der Variablen niemals verwendet wird . constWeist den Compiler an, den Wert sofort zu ersetzen (anstatt ihm ein Register zuzuweisen oder ihn aus dem Speicher zu laden) und die lokale Variable als Standardverhalten in den Stapel zu schreiben. const registerist die Kombination dieser ermutigten Optimierungen. Dies ist so schlank wie es nur geht.
Außerdem registerscheint es unter gcc C und C ++ für sich genommen eine zufällige 16-Byte-Lücke im Stapel für das erste lokale Element im Stapel zu geben, was bei nicht der Fall ist const register.
Kompilieren mit -Ofast jedoch; registerhat 0 Optimierungseffekt, denn wenn es in ein Register aufgenommen oder sofort erstellt werden kann, wird es immer sein und wenn es nicht kann, wird es nicht sein; constoptimiert weiterhin die Auslastung von C und C ++, jedoch nur im Dateibereich ; volatileErzwingt weiterhin, dass die Werte gespeichert und vom Stapel geladen werden.
.LC0:
.string "%d"
main:
//optimises out push and change of rbp
sub rsp, 8 //https://stackoverflow.com/a/40344912/7194773
mov esi, 3
mov edi, OFFSET FLAT:.LC0
xor eax, eax //xor 2 bytes vs 5 for mov eax, 0
call printf
xor eax, eax
add rsp, 8
ret