Alle Antworten sind ausgezeichnet. Darüber hinaus möchte ich ein Beispiel nennen.
Unten ist ein kleines CPP-Programm:
#include <iostream>
int x;
int main(){
char buf[50];
x = 8;
if(x == 8)
printf("x is 8\n");
else
sprintf(buf, "x is not 8\n");
x=1000;
while(x > 5)
x--;
return 0;
}
Lassen Sie uns nun die Assembly des obigen Codes generieren (und ich werde nur die Teile der Assembly einfügen, die hier relevant sind):
Der Befehl zum Generieren einer Assembly:
g++ -S -O3 -c -fverbose-asm -Wa,-adhln assembly.cpp
Und die Versammlung:
main:
.LFB1594:
subq $40, %rsp #,
.seh_stackalloc 40
.seh_endprologue
# assembly.cpp:5: int main(){
call __main #
# assembly.cpp:10: printf("x is 8\n");
leaq .LC0(%rip), %rcx #,
# assembly.cpp:7: x = 8;
movl $8, x(%rip) #, x
# assembly.cpp:10: printf("x is 8\n");
call _ZL6printfPKcz.constprop.0 #
# assembly.cpp:18: }
xorl %eax, %eax #
movl $5, x(%rip) #, x
addq $40, %rsp #,
ret
.seh_endproc
.p2align 4,,15
.def _GLOBAL__sub_I_x; .scl 3; .type 32; .endef
.seh_proc _GLOBAL__sub_I_x
Sie können in der Assembly sehen, dass der Assemblycode nicht generiert wurde, sprintfda der Compiler davon ausgegangen ist, dass xsich dies außerhalb des Programms nicht ändert. Gleiches gilt für die whileSchleife. whileSchleife wurde insgesamt aufgrund der Optimierung entfernt , da Compiler sie als nutzlos Code sah und somit direkt zugeordnet 5zu x(siehe movl $5, x(%rip)).
Das Problem tritt auf, wenn ein externer Prozess / eine externe Hardware den Wert von xirgendwo zwischen x = 8;und ändern würde if(x == 8). Wir würden erwarten else, dass Block funktioniert, aber leider hat der Compiler diesen Teil herausgeschnitten.
Nun, um dieses Problem zu lösen, in der assembly.cpp, lassen Sie uns ändern int x;zu volatile int x;schnell und die Assembler - Code sehen erzeugt:
main:
.LFB1594:
subq $104, %rsp #,
.seh_stackalloc 104
.seh_endprologue
# assembly.cpp:5: int main(){
call __main #
# assembly.cpp:7: x = 8;
movl $8, x(%rip) #, x
# assembly.cpp:9: if(x == 8)
movl x(%rip), %eax # x, x.1_1
# assembly.cpp:9: if(x == 8)
cmpl $8, %eax #, x.1_1
je .L11 #,
# assembly.cpp:12: sprintf(buf, "x is not 8\n");
leaq 32(%rsp), %rcx #, tmp93
leaq .LC0(%rip), %rdx #,
call _ZL7sprintfPcPKcz.constprop.0 #
.L7:
# assembly.cpp:14: x=1000;
movl $1000, x(%rip) #, x
# assembly.cpp:15: while(x > 5)
movl x(%rip), %eax # x, x.3_15
cmpl $5, %eax #, x.3_15
jle .L8 #,
.p2align 4,,10
.L9:
# assembly.cpp:16: x--;
movl x(%rip), %eax # x, x.4_3
subl $1, %eax #, _4
movl %eax, x(%rip) # _4, x
# assembly.cpp:15: while(x > 5)
movl x(%rip), %eax # x, x.3_2
cmpl $5, %eax #, x.3_2
jg .L9 #,
.L8:
# assembly.cpp:18: }
xorl %eax, %eax #
addq $104, %rsp #,
ret
.L11:
# assembly.cpp:10: printf("x is 8\n");
leaq .LC1(%rip), %rcx #,
call _ZL6printfPKcz.constprop.1 #
jmp .L7 #
.seh_endproc
.p2align 4,,15
.def _GLOBAL__sub_I_x; .scl 3; .type 32; .endef
.seh_proc _GLOBAL__sub_I_x
Hier können Sie sehen , dass die Montage - Codes für sprintf, printfund whileSchleife erzeugt wurden. Der Vorteil ist, dass ein Teil des Codes ausgeführt wird, wenn die xVariable durch ein externes Programm oder eine externe Hardware geändert sprintfwird. In ähnlicher Weise whilekann die Schleife jetzt zum Warten verwendet werden.