源码
#include "stdio.h"int main(void)
{int i = 1;printf("%d\n",(++i) +(++i));return 0;
}
执行
weiqifa@bsp-ubuntu1804:~/c/undif$ gcc g.c && ./a.out
6
weiqifa@bsp-ubuntu1804:~/c/undif$
为什么出现这个鬼现象?
原因很简单,C语言的法律里面没有定义这条规格,这个属于C语言的未定义行为,也就是擦边球,什么是擦边球呢?就是这些行为不是错误的行为,法律没有明确定义的,所以就是擦边球。
它的执行顺序是这样的
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.p .rodata
.LC0:.string "%d\n".text.globl main.type main, @function
main:
.LFB0:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $16, %rspmovl $1, -4(%rbp)addl $1, -4(%rbp)addl $1, -4(%rbp)movl -4(%rbp), %eaxaddl %eax, %eaxmovl %eax, %esileaq .LC0(%rip), %rdimovl $0, %eaxcall printf@PLTmovl $0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE0:.size main, .-main.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0".p .note.GNU-stack,"",@progbits
weiqifa@bsp-ubuntu1804:~/c/undif$ ls
我们不用关注所有的代码,分析下面几行关键的
subq $16, %rsp
movl $1, -4(%rbp) //相当于 i = 1
addl $1, -4(%rbp) //相当于 i +1
addl $1, -4(%rbp) //相当于 i +1
movl -4(%rbp), %eax // 把rbp寄存器传给eax寄存器
addl %eax, %eax //相当于 i + i
看完这个代码后,应该知道为啥输出的是 6 了吧?
最后
我认为一个是编译器执行顺序的问题,反汇编无非就是搞清楚C的执行顺序,而且我认为研究这个是有意义的,不过有意义不代表可以这样写代码。
C本身是偏底层的东西,了解编译的原理和过程是非常重要的。
但是了解也不能这样瞎用,还是要遵守规则,要不然,这样导致的bug估计要害死很多人。
推荐阅读:
专辑|Linux文章汇总
专辑|程序人生
嵌入式Linux
微信扫描二维码,关注我的公众号