你真正的了解i++和++i吗?
Posted 啊渊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你真正的了解i++和++i吗?相关的知识,希望对你有一定的参考价值。
一个菜鸟新手问题,佬大你知道以下代码的运行结果吗?
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。
好吧!!学到了吧。
以上是关于你真正的了解i++和++i吗?的主要内容,如果未能解决你的问题,请参考以下文章