一個菜鳥新手問題,佬大你知道以下代碼的運行結果嗎?
int x=3;
int y=(++x)+(++x)+(++x);
我自豪的答到,這個不簡單嗎?15
因為++x =4,每一次x的值都被改變+1,因此y=4+5+6 = 15.
菜鳥說,是不是電腦壞了,你過來看看運行結果,
y = 16,

大型翻車現場,
我立馬寫了一份代碼:main.c
#include <stdio.h>
int main(int agrc,char** args){
int x = 3,y,z1 ,z2,z3,res;
z1=(++x);
printf("z1:%d,x:%d\n",z1,x);
z2=(++x);
printf("z2:%d,x:%d\n",z2,x);
z3=(++x);
printf("z3:%d,x:%d\n",z3,x);
res = z1 + z2 + z3;
printf("res:%d\n",res);
x = 3;
y=(++x)+(++x)+(++x);
printf("y:%d\n",y);
return 0;
}
編譯代碼如下:
gcc main.c -o main
./main
## 運行結果
z1:4,x:4
z2:5,x:5
z3:6,x:6
res:15
y:16
奇了怪了,為啥一個是15,一個是16.
旁邊的同事提醒我,你用clang編譯試試,
編譯代碼如下:
clang main.c -o main
./main
## 運行結果
z1:4,x:4
z2:5,x:5
z3:6,x:6
res:15
y:15
兩種編譯器,代碼相同運行結果還不一樣!!!!!
gcc 分析
為了方便查看我將代碼修改以下代碼:
#include <stdio.h>
int main(int agrc,char** args){
int x = 3,y;
y=(++x)+(++x)+(++x);
printf("y:%d\n",y);
return 0;
}
編譯
gcc -g test.c -o testcc
gdb testcc
輸入 l查看代碼:

輸入 b 5,在第5行打斷點,

運行到第五行停止,

disassenble 查看匯編代碼


加法分析
0x0000000000401131 <+15>: movl $0x3,-0x4(%rbp) # 賦值給x ,暫存器rbp的值等于3
0x0000000000401138 <+22>: addl $0x1,-0x4(%rbp) # x+1 ,暫存器rbp的值等于4
0x000000000040113c <+26>: addl $0x1,-0x4(%rbp) # x+1 ,暫存器rbp的值等于5
0x0000000000401140 <+30>: mov -0x4(%rbp),%eax # 將rbp的值放入到eax暫存器,eax的值等于5,rax也等于5
0x0000000000401143 <+33>: lea (%rax,%rax,1),%edx # 這個時候y=(++x)+(++x) 指令mov (%rax+%ras*1) edx,會發現這個時候rax的值是5,所以edx的值是10!!!!!
0x0000000000401146 <+36>: addl $0x1,-0x4(%rbp) # x+1 ,暫存器rbp的值等于6
0x000000000040114a <+40>: mov -0x4(%rbp),%eax
0x000000000040114d <+43>: add %edx,%eax # 6+10 ,所以結果是16
除錯技巧
p $rbp-4 // 獲取rbp的地址
p *(0x7fffffffde1c) // 列印值
b 0x0000000000401131 // 打斷點
clang 分析
#include <stdio.h>
int main(int agrc,char** args){
int x = 3,y;
y=(++x)+(++x)+(++x);
printf("y:%d\n",y);
return 0;
}
編譯
clang -g test.c -o testclang
gdb testclang
main.c:13:5: warning: multiple unsequenced modifications to 'x' [-Wunsequenced]
y=(++x)+(++x)+(++x);
^ ~~
1 warning generated.
使用gdb查看

0x0000000000401146 <+22>: movl $0x3,-0x14(%rbp) # 給x賦值為3
0x000000000040114d <+29>: mov -0x14(%rbp),%edi # 將x的值保存在edi暫存器
0x0000000000401150 <+32>: add $0x1,%edi # edi +1 暫存器 edi值等于4
0x0000000000401153 <+35>: mov %edi,-0x14(%rbp) # 保存rpb的值
0x0000000000401156 <+38>: mov -0x14(%rbp),%eax # 將x的值保存在eax暫存器 4
0x0000000000401159 <+41>: add $0x1,%eax # edi +1 暫存器 edi值等于5
0x000000000040115c <+44>: mov %eax,-0x14(%rbp) # 保存rpb的值 5
0x000000000040115f <+47>: add %eax,%edi # 相加!!關鍵,看到了嗎?這里是兩個暫存器所以不會 4+ 5=9
0x0000000000401161 <+49>: mov -0x14(%rbp),%eax
0x0000000000401164 <+52>: add $0x1,%eax # eax +1 暫存器 eax值等于6
0x0000000000401167 <+55>: mov %eax,-0x14(%rbp)
0x000000000040116a <+58>: add %eax,%edi
0x000000000040116c <+60>: mov %edi,-0x18(%rbp)
0x000000000040116f <+63>: mov -0x18(%rbp),%esi
0x0000000000401172 <+66>: movabs $0x402004,%rdi
所以他的運行結果是15,
好吧!!學到了吧,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/339216.html
標籤:其他
