++a和a++的相关问题
来源:互联网 发布:sql语句括号的用法 编辑:程序博客网 时间:2024/05/18 02:51
int a=1;
int b,c;
b=(a++)+(a++)+(a++);
//计算结果:b=3,a=4
int a=1;
c=(++a)+(++a)+(++a);
//计算结果:c=10,a=4
为什么c=10呢?
结果与编译器有关,gcc得出的结果也是10。
下面是一个测试的源代码:
int main(int argc, char argv[])
{
int a = 1;
int b,c;
b = (a++)+(a++)+(a++);
printf("b = %d, a = %d./n", b, a); // b = 3, a = 4.
a = 1;
c = (++a) + (++a) + (++a);
printf("c = %d, a = %d./n", c, a); // b = 10, a = 4
return 1;
}
下面是在Linux环境下通过反汇编得到的源程序和汇编代码混合的文件,这里只给出main函数。
int main(int argc, char argv[])
{
8048328: 55 push %ebp
8048329: 89 e5 mov %esp,%ebp
804832b: 83 ec 18 sub $0x18,%esp
804832e: 83 e4 f0 and $0xfffffff0,%esp
8048331: b8 00 00 00 00 mov $0x0,%eax
8048336: 29 c4 sub %eax,%esp
int a = 1;
8048338: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 0xfffffffc(%ebp) 存放的是临时变量a
int b,c;
b = (a++)+(a++)+(a++);
804833f: 8b 55 fc mov 0xfffffffc(%ebp),%edx // a->edx
8048342: 8b 45 fc mov 0xfffffffc(%ebp),%eax // a->eax
8048345: 01 c2 add %eax,%edx // a + a -> edx, eax = a
8048347: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804834a: 8d 04 10 lea (%eax,%edx,1),%eax // ?
804834d: 89 45 f8 mov %eax,0xfffffff8(%ebp) // b = (a++)+(a++)+(a++).这里结果存放在临时变量b
8048350: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax 指向临时变量a,这里执行的是三个a++.
8048353: ff 00 incl (%eax)
8048355: 8d 45 fc lea 0xfffffffc(%ebp),%eax
8048358: ff 00 incl (%eax)
804835a: 8d 45 fc lea 0xfffffffc(%ebp),%eax
804835d: ff 00 incl (%eax)
printf("b = %d, a = %d./n", b, a);
804835f: 83 ec 04 sub $0x4,%esp
8048362: ff 75 fc pushl 0xfffffffc(%ebp)
8048365: ff 75 f8 pushl 0xfffffff8(%ebp)
8048368: 68 64 84 04 08 push $0x8048464
804836d: e8 f6 fe ff ff call 8048268 <_init+0x38>
8048372: 83 c4 10 add $0x10,%esp
a = 1;
8048375: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 临时变量 a被赋予初值1
c = (++a) + (++a) + (++a);
804837c: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
804837f: ff 00 incl (%eax) // ++a
8048381: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
8048384: ff 00 incl (%eax) // ++a
8048386: 8b 45 fc mov 0xfffffffc(%ebp),%eax // 此时a应该等于3
8048389: 8b 55 fc mov 0xfffffffc(%ebp),%edx // edx指向临时变量a
804838c: 01 c2 add %eax,%edx // edx = eax + edx
804838e: 8d 45 fc lea 0xfffffffc(%ebp),%eax // ++a
8048391: ff 00 incl (%eax)
8048393: 89 d0 mov %edx,%eax // edx->eax
8048395: 03 45 fc add 0xfffffffc(%ebp),%eax
8048398: 89 45 f4 mov %eax,0xfffffff4(%ebp) // 结果存放到c中去
printf("c = %d, a = %d./n", c, a);
804839b: 83 ec 04 sub $0x4,%esp
804839e: ff 75 fc pushl 0xfffffffc(%ebp)
80483a1: ff 75 f4 pushl 0xfffffff4(%ebp)
80483a4: 68 75 84 04 08 push $0x8048475
80483a9: e8 ba fe ff ff call 8048268 <_init+0x38>
80483ae: 83 c4 10 add $0x10,%esp
return 1;
80483b1: b8 01 00 00 00 mov $0x1,%eax
}
80483b6: c9 leave
80483b7: c3 ret
可以看出:
1。第1个式子b = (a++)+(a++)+(a++);的编译器的编译结果是:
先将3个a的值相加,结果存放在临时变量b中。然后,三次增加临时变量a的值。
int a = 1;
8048338: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 0xfffffffc(%ebp) 存放的是临时变量a
int b,c;
b = (a++)+(a++)+(a++);
804833f: 8b 55 fc mov 0xfffffffc(%ebp),%edx // a->edx
8048342: 8b 45 fc mov 0xfffffffc(%ebp),%eax // a->eax
8048345: 01 c2 add %eax,%edx // a + a -> edx, eax = a
8048347: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804834a: 8d 04 10 lea (%eax,%edx,1),%eax // ?
804834d: 89 45 f8 mov %eax,0xfffffff8(%ebp) // b = (a++)+(a++)+(a++).这里结果存放在临时变量b
8048350: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax 指向临时变量a,这里执行的是三个a++.
8048353: ff 00 incl (%eax)
8048355: 8d 45 fc lea 0xfffffffc(%ebp),%eax
8048358: ff 00 incl (%eax)
804835a: 8d 45 fc lea 0xfffffffc(%ebp),%eax
804835d: ff 00 incl (%eax)
2。第2个式子,其做法就不同。
实际做法是:
-。首先执行第一个++a,方法是gcc把a的地址放进寄存器%eax,然后incl(%eax);
然后解析表达式,遇到后面是+号,加法是需要左值和右值的,所以还要计算右值;
-。然后执行第二个++a,方法也是gcc把a的地址放进寄存器%eax,然后incl(%eax);
此时a的值是3。
-。这个时候左值和右值都有了,可以运行加法了,但是这个时候的a变成了3;
这里的加法是a的值分别取到edx和eax中,然后相加,
所以加出来的值就是3+3=6;这个临时值被放进了一个寄存器(这里是%edx);
上面的例子中又+(++a);这个时候再把a的地址放进寄存器%eax,然后incl(%eax)
-。最后把%edx和a的值相加就可以了;
这里的关键是第1个++a中,表达式(++a)的值没有使用临时变量来缓存,到执行加法的时候是直接再从临时变量a取的值。
a = 1;
8048375: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 临时变量 a被赋予初值1
c = (++a) + (++a) + (++a);
804837c: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
804837f: ff 00 incl (%eax) // ++a
8048381: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
8048384: ff 00 incl (%eax) // ++a
8048386: 8b 45 fc mov 0xfffffffc(%ebp),%eax // 此时a应该等于3
8048389: 8b 55 fc mov 0xfffffffc(%ebp),%edx // edx指向临时变量a
804838c: 01 c2 add %eax,%edx // edx = eax + edx
804838e: 8d 45 fc lea 0xfffffffc(%ebp),%eax // ++a
8048391: ff 00 incl (%eax)
8048393: 89 d0 mov %edx,%eax // edx->eax
8048395: 03 45 fc add 0xfffffffc(%ebp),%eax
8048398: 89 45 f4 mov %eax,0xfffffff4(%ebp) // 结果存放到c中去
结论:
这里只是在VC和Linux环境下的gcc中做过验证,其他环境尚不清楚。
结论就是如果需要明确的结果,建议去掉这种可能产生歧义的表达式。
int b,c;
b=(a++)+(a++)+(a++);
//计算结果:b=3,a=4
int a=1;
c=(++a)+(++a)+(++a);
//计算结果:c=10,a=4
为什么c=10呢?
结果与编译器有关,gcc得出的结果也是10。
下面是一个测试的源代码:
int main(int argc, char argv[])
{
int a = 1;
int b,c;
b = (a++)+(a++)+(a++);
printf("b = %d, a = %d./n", b, a); // b = 3, a = 4.
a = 1;
c = (++a) + (++a) + (++a);
printf("c = %d, a = %d./n", c, a); // b = 10, a = 4
return 1;
}
下面是在Linux环境下通过反汇编得到的源程序和汇编代码混合的文件,这里只给出main函数。
int main(int argc, char argv[])
{
8048328: 55 push %ebp
8048329: 89 e5 mov %esp,%ebp
804832b: 83 ec 18 sub $0x18,%esp
804832e: 83 e4 f0 and $0xfffffff0,%esp
8048331: b8 00 00 00 00 mov $0x0,%eax
8048336: 29 c4 sub %eax,%esp
int a = 1;
8048338: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 0xfffffffc(%ebp) 存放的是临时变量a
int b,c;
b = (a++)+(a++)+(a++);
804833f: 8b 55 fc mov 0xfffffffc(%ebp),%edx // a->edx
8048342: 8b 45 fc mov 0xfffffffc(%ebp),%eax // a->eax
8048345: 01 c2 add %eax,%edx // a + a -> edx, eax = a
8048347: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804834a: 8d 04 10 lea (%eax,%edx,1),%eax // ?
804834d: 89 45 f8 mov %eax,0xfffffff8(%ebp) // b = (a++)+(a++)+(a++).这里结果存放在临时变量b
8048350: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax 指向临时变量a,这里执行的是三个a++.
8048353: ff 00 incl (%eax)
8048355: 8d 45 fc lea 0xfffffffc(%ebp),%eax
8048358: ff 00 incl (%eax)
804835a: 8d 45 fc lea 0xfffffffc(%ebp),%eax
804835d: ff 00 incl (%eax)
printf("b = %d, a = %d./n", b, a);
804835f: 83 ec 04 sub $0x4,%esp
8048362: ff 75 fc pushl 0xfffffffc(%ebp)
8048365: ff 75 f8 pushl 0xfffffff8(%ebp)
8048368: 68 64 84 04 08 push $0x8048464
804836d: e8 f6 fe ff ff call 8048268 <_init+0x38>
8048372: 83 c4 10 add $0x10,%esp
a = 1;
8048375: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 临时变量 a被赋予初值1
c = (++a) + (++a) + (++a);
804837c: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
804837f: ff 00 incl (%eax) // ++a
8048381: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
8048384: ff 00 incl (%eax) // ++a
8048386: 8b 45 fc mov 0xfffffffc(%ebp),%eax // 此时a应该等于3
8048389: 8b 55 fc mov 0xfffffffc(%ebp),%edx // edx指向临时变量a
804838c: 01 c2 add %eax,%edx // edx = eax + edx
804838e: 8d 45 fc lea 0xfffffffc(%ebp),%eax // ++a
8048391: ff 00 incl (%eax)
8048393: 89 d0 mov %edx,%eax // edx->eax
8048395: 03 45 fc add 0xfffffffc(%ebp),%eax
8048398: 89 45 f4 mov %eax,0xfffffff4(%ebp) // 结果存放到c中去
printf("c = %d, a = %d./n", c, a);
804839b: 83 ec 04 sub $0x4,%esp
804839e: ff 75 fc pushl 0xfffffffc(%ebp)
80483a1: ff 75 f4 pushl 0xfffffff4(%ebp)
80483a4: 68 75 84 04 08 push $0x8048475
80483a9: e8 ba fe ff ff call 8048268 <_init+0x38>
80483ae: 83 c4 10 add $0x10,%esp
return 1;
80483b1: b8 01 00 00 00 mov $0x1,%eax
}
80483b6: c9 leave
80483b7: c3 ret
可以看出:
1。第1个式子b = (a++)+(a++)+(a++);的编译器的编译结果是:
先将3个a的值相加,结果存放在临时变量b中。然后,三次增加临时变量a的值。
int a = 1;
8048338: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 0xfffffffc(%ebp) 存放的是临时变量a
int b,c;
b = (a++)+(a++)+(a++);
804833f: 8b 55 fc mov 0xfffffffc(%ebp),%edx // a->edx
8048342: 8b 45 fc mov 0xfffffffc(%ebp),%eax // a->eax
8048345: 01 c2 add %eax,%edx // a + a -> edx, eax = a
8048347: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804834a: 8d 04 10 lea (%eax,%edx,1),%eax // ?
804834d: 89 45 f8 mov %eax,0xfffffff8(%ebp) // b = (a++)+(a++)+(a++).这里结果存放在临时变量b
8048350: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax 指向临时变量a,这里执行的是三个a++.
8048353: ff 00 incl (%eax)
8048355: 8d 45 fc lea 0xfffffffc(%ebp),%eax
8048358: ff 00 incl (%eax)
804835a: 8d 45 fc lea 0xfffffffc(%ebp),%eax
804835d: ff 00 incl (%eax)
2。第2个式子,其做法就不同。
实际做法是:
-。首先执行第一个++a,方法是gcc把a的地址放进寄存器%eax,然后incl(%eax);
然后解析表达式,遇到后面是+号,加法是需要左值和右值的,所以还要计算右值;
-。然后执行第二个++a,方法也是gcc把a的地址放进寄存器%eax,然后incl(%eax);
此时a的值是3。
-。这个时候左值和右值都有了,可以运行加法了,但是这个时候的a变成了3;
这里的加法是a的值分别取到edx和eax中,然后相加,
所以加出来的值就是3+3=6;这个临时值被放进了一个寄存器(这里是%edx);
上面的例子中又+(++a);这个时候再把a的地址放进寄存器%eax,然后incl(%eax)
-。最后把%edx和a的值相加就可以了;
这里的关键是第1个++a中,表达式(++a)的值没有使用临时变量来缓存,到执行加法的时候是直接再从临时变量a取的值。
a = 1;
8048375: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp) // 临时变量 a被赋予初值1
c = (++a) + (++a) + (++a);
804837c: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
804837f: ff 00 incl (%eax) // ++a
8048381: 8d 45 fc lea 0xfffffffc(%ebp),%eax // eax指向临时变量a
8048384: ff 00 incl (%eax) // ++a
8048386: 8b 45 fc mov 0xfffffffc(%ebp),%eax // 此时a应该等于3
8048389: 8b 55 fc mov 0xfffffffc(%ebp),%edx // edx指向临时变量a
804838c: 01 c2 add %eax,%edx // edx = eax + edx
804838e: 8d 45 fc lea 0xfffffffc(%ebp),%eax // ++a
8048391: ff 00 incl (%eax)
8048393: 89 d0 mov %edx,%eax // edx->eax
8048395: 03 45 fc add 0xfffffffc(%ebp),%eax
8048398: 89 45 f4 mov %eax,0xfffffff4(%ebp) // 结果存放到c中去
结论:
这里只是在VC和Linux环境下的gcc中做过验证,其他环境尚不清楚。
结论就是如果需要明确的结果,建议去掉这种可能产生歧义的表达式。
- ++a和a++的相关问题
- a++和++a的问题
- 关于 (++a)+(++a)+(++a) 和 (a++)+(a++)+(a++) 问题
- NYOJ A : 和的问题
- A/D转换相关问题
- (++a)+=(a++)和(++a)=(++a)+(a++)的区别
- (++a)+=(a++)和(++a)=(++a)+(a++)的区别
- 求Sn=a+a*a+a*a*a+a*a*a*a的和,其中a是一个数字。
- 关于数组a[3] 和3[a]的问题
- 关于自增运算符++a和a++的问题
- 关于C语言中a++和++a的问题
- Android 定位相关技术及会遇到的问题A
- 数组a[],a和&a的区别
- 关于'a++'和'++a'和'a+5'是否能作左值的问题
- 如何解决 a+b >c 和 a*b 和 a-b 的 integer overflow 问题
- a 和&a的区别
- a和&a的区别
- a 和&a 的区别
- 查询本机IP
- web 打印分页page-break-after
- 计算机技术与软件专业技术资格(水平)考试
- Eclipse基础--Eclipse启动过程
- .net wap 开发:在.net中写自己的objectlist
- ++a和a++的相关问题
- 我和春天有个约会(一)
- 关闭U盘自动播放功能
- Gif图片在提交时,在IE中不能正常工作
- win2003解决IIS限制上传文件的大小
- 失望!Boost1.32的FileSystem居然是基于string的!
- 失败
- Debug和Release之本质区别
- 今天发现了把DataGrid导出Excel时格式化字符串的方法。