Toutes les réponses sont excellentes. Mais en plus de cela, je voudrais partager un exemple.
Voici un petit programme cpp:
#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;
}
Maintenant, permet de générer l'assembly du code ci-dessus (et je ne collerai que les parties de l'assembly pertinentes ici):
La commande pour générer l'assembly:
g++ -S -O3 -c -fverbose-asm -Wa,-adhln assembly.cpp
Et l'assemblage:
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
Vous pouvez voir dans l'assembly que le code d'assembly n'a pas été généré sprintf
car le compilateur a supposé que x
cela ne changera pas en dehors du programme. Et c'est le cas avec la while
boucle. while
La boucle a été complètement supprimée en raison de l'optimisation car le compilateur l'a vue comme un code inutile et donc directement affectée 5
à x
(voirmovl $5, x(%rip)
).
Le problème se produit lorsque que se passe-t-il si un processus / matériel externe change la valeur de x
quelque part entre x = 8;
et if(x == 8)
. Nous nous attendions à ce que le else
bloc fonctionne, mais malheureusement, le compilateur a supprimé cette partie.
Maintenant, afin de résoudre ce problème, en assembly.cpp
, changeons int x;
de volatile int x;
et voir rapidement le code assembleur généré:
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
Ici vous pouvez voir que les codes d'assemblage pour sprintf
, printf
et la while
boucle ont été générés. L'avantage est que si la x
variable est modifiée par un programme ou un matériel externe, une sprintf
partie du code sera exécutée. Et de même, la while
boucle peut être utilisée pour une attente occupée maintenant.