源碼
#include 'stdio.h'
int main(void)
{
int i = 1;
printf('%d\n',(++i) +(++i));
return 0;
}
執(zhí)行
weiqifa@bsp-ubuntu1804:~/c/undif$ gcc g.c && ./a.out
6
weiqifa@bsp-ubuntu1804:~/c/undif$
為什么出現(xiàn)這個鬼現(xiàn)象?
原因很簡單,C語言的法律里面沒有定義這條規(guī)格,這個屬于C語言的未定義行為,也就是擦邊球,什么是擦邊球呢?就是這些行為不是錯誤的行為,法律沒有明確定義的,所以就是擦邊球。
它的執(zhí)行順序是這樣的
int i = 1;
++i ;//i = 2
++i ;//i = 3
i + i ; //輸出6
反匯編看看
weiqifa@bsp-ubuntu1804:~/c/undif$ gcc -S g.c
weiqifa@bsp-ubuntu1804:~/c/undif$ cat g.s
.file 'g.c'
.text
.section .rodata
.LC0:
.string '%d\n'
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $1, -4(%rbp)
addl $1, -4(%rbp)
addl $1, -4(%rbp)
movl -4(%rbp), %eax
addl %eax, %eax
movl %eax, %esi
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident 'GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0'
.section .note.GNU-stack,'',@progbits
weiqifa@bsp-ubuntu1804:~/c/undif$ ls
我們不用關(guān)注所有的代碼,分析下面幾行關(guān)鍵的
subq $16, %rsp
movl $1, -4(%rbp) //相當(dāng)于 i = 1
addl $1, -4(%rbp) //相當(dāng)于 i +1
addl $1, -4(%rbp) //相當(dāng)于 i +1
movl -4(%rbp), %eax // 把rbp寄存器傳給eax寄存器
addl %eax, %eax //相當(dāng)于 i + i
看完這個代碼后,應(yīng)該知道為啥輸出的是 6 了吧?
最后
我認(rèn)為一個是編譯器執(zhí)行順序的問題,反匯編無非就是搞清楚C的執(zhí)行順序,而且我認(rèn)為研究這個是有意義的,不過有意義不代表可以這樣寫代碼。
C本身是偏底層的東西,了解編譯的原理和過程是非常重要的。
但是了解也不能這樣瞎用,還是要遵守規(guī)則,要不然,這樣導(dǎo)致的bug估計要害死很多人。