Tất cả các câu trả lời là tuyệt vời. Nhưng trên hết, tôi muốn chia sẻ một ví dụ.
Dưới đây là một chương trình cpp nhỏ:
#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;
}
Bây giờ, hãy tạo tập hợp mã ở trên (và tôi sẽ chỉ dán các phần của tập hợp có liên quan ở đây):
Lệnh tạo lắp ráp:
g++ -S -O3 -c -fverbose-asm -Wa,-adhln assembly.cpp
Và lắp ráp:
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
Bạn có thể thấy trong hội đồng mà mã lắp ráp không được tạo sprintfvì trình biên dịch giả định rằng nó xsẽ không thay đổi bên ngoài chương trình. Và tương tự là trường hợp với whilevòng lặp. whilevòng lặp đã bị loại bỏ hoàn toàn do tối ưu hóa vì trình biên dịch đã xem nó như một mã vô dụng và do đó được gán trực tiếp 5cho x(xem movl $5, x(%rip)).
Vấn đề xảy ra khi điều gì xảy ra nếu một quy trình / phần cứng bên ngoài sẽ thay đổi giá trị của xmột nơi nào đó giữa x = 8;và if(x == 8). Chúng tôi hy vọng elsekhối sẽ hoạt động nhưng không may là trình biên dịch đã cắt bỏ phần đó.
Bây giờ, để giải quyết việc này, trong assembly.cpp, chúng ta hãy thay đổi int x;để volatile int x;và nhanh chóng xem mã lắp ráp tạo ra:
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
Ở đây bạn có thể thấy rằng các mã lắp ráp cho sprintf, printfvà whilevòng lặp đã được tạo ra. Ưu điểm là nếu xbiến được thay đổi bởi một số chương trình hoặc phần cứng bên ngoài, sprintfmột phần của mã sẽ được thực thi. Và whilevòng lặp tương tự có thể được sử dụng cho chờ đợi bận rộn bây giờ.