14
回答
一个关于自增的奇怪问题
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   
#include "stdio.h"
int main()

{
int i=1;
    int k=(i++)*(i++);
printf("%d %d\n",k,i);
return 0;
}
我用VC运行得到的结果是1 3
但我感觉而且有些书上的结果也是2 3
谁可以帮我解释下
举报
阮文明
发帖于5年前 14回/491阅
共有14个答案 最后回答: 5年前

看生成的汇编代码非常直观:

对于 int k=(i++)*(i++); 编译器是做 i * i, 然后做 i++, i++

	int i=1;
00B6944E  mov         dword ptr [i],1  

	int k=(i++)*(i++);
00B69455  mov         eax,dword ptr [i]  
00B69458  imul        eax,dword ptr [i]  // 乘法
00B6945C  mov         dword ptr [k],eax  
00B6945F  mov         ecx,dword ptr [i]  // i++
00B69462  add         ecx,1  
00B69465  mov         dword ptr [i],ecx  
00B69468  mov         edx,dword ptr [i]  // i++
00B6946B  add         edx,1  
00B6946E  mov         dword ptr [i],edx  


对于 int k = (++i)*(++i); 编译器做 i++,i++后在 i*i

00C6944E  mov         dword ptr [i],1  

	int k=(++i)*(++i);
00C69455  mov         eax,dword ptr [i]  // ++i
00C69458  add         eax,1  
00C6945B  mov         dword ptr [i],eax  
00C6945E  mov         ecx,dword ptr [i]  // ++i
00C69461  add         ecx,1  
00C69464  mov         dword ptr [i],ecx  
00C69467  mov         edx,dword ptr [i]  
00C6946A  imul        edx,dword ptr [i]  //乘法
00C6946E  mov         dword ptr [k],edx  


--- 共有 3 条评论 ---
莫肖回复 @billzheng : 嗯嗯,了解了,thankyou…^_^ 5年前 回复
billzheng回复 @莫肖 : 如果你用Visual studio 调试代码,设置断点,运行至断点,菜单:Debug->Windows->Disassembly 或者Alt+ 8快捷键. Linux 下参考Gcc/G++生成asm代码 5年前 回复
莫肖弱弱的问哈子,这些asm代码怎么生成的啊? 5年前 回复
这种运算的时间是以语句来衡量的,也就是后自加 这个就是说在int k=(i++)*(i++);这个语句执行完毕后在进行自加,也就是说int k=(i++)*(i++);这个语句生命期内i始终是1,语句结束后进行两次后自加而已,int k=(++i)*(i++);你看着个是多少呢,答案是4 为什么呢,因为前自加是在语句执行前进行自加,也就是说i先自加到2了,然后开始执行int k=(++i)*(i++);这个语句,那么自然k就是4
对于 int k=(i++)*(i++); 编译器是做 i * i, 然后做 i++, i++

  不是() 优先级大于 * 得么,那为什么还是先 *  后 ()得呢?

我是菜鸟,

--- 共有 1 条评论 ---
zzrgo()的优先级确实大于*,但是,i++等价于这样一个函数。 int iPlusPlus(int i) { int temp = i; ++i; return temp; }; 也就是说(i++),其实是返回的是i的一个没有自增的副本。这就你现在造成了你对优先级的误解。 5年前 回复

标准没看仔细。

首先,求值顺序和优先级没有关系,例如:

a*b+c,没有规定说一定要先对a和b求值,再对c求值,编译器完全可以先对c求值,缓存在什么地方,然后再去算a*b。

其次,在两个Sequence Point之间多次改变同一个变量的值是错误的,其结果是“undefined”,也就是说,执行这样的程序会导致什么结果是未知的,可能让你的计算机爆炸,也可能导致火星撞地球。如果是书上出现了这样的题,你应该做的是把这本书拿起来,扔进离你最近的一个垃圾桶。

关于Sequence Point的定义参考http://en.wikipedia.org/wiki/Sequence_point

 

++右结合,可是你是后置的,右边没值,所以在';'读入后进行运算,排在所有的运算后面再++两次。

引用来自“billzheng”的答案

看生成的汇编代码非常直观:

对于 int k=(i++)*(i++); 编译器是做 i * i, 然后做 i++, i++

	int i=1;
00B6944E  mov         dword ptr [i],1  

	int k=(i++)*(i++);
00B69455  mov         eax,dword ptr [i]  
00B69458  imul        eax,dword ptr [i]  // 乘法
00B6945C  mov         dword ptr [k],eax  
00B6945F  mov         ecx,dword ptr [i]  // i++
00B69462  add         ecx,1  
00B69465  mov         dword ptr [i],ecx  
00B69468  mov         edx,dword ptr [i]  // i++
00B6946B  add         edx,1  
00B6946E  mov         dword ptr [i],edx  


对于 int k = (++i)*(++i); 编译器做 i++,i++后在 i*i

00C6944E  mov         dword ptr [i],1  

	int k=(++i)*(++i);
00C69455  mov         eax,dword ptr [i]  // ++i
00C69458  add         eax,1  
00C6945B  mov         dword ptr [i],eax  
00C6945E  mov         ecx,dword ptr [i]  // ++i
00C69461  add         ecx,1  
00C69464  mov         dword ptr [i],ecx  
00C69467  mov         edx,dword ptr [i]  
00C6946A  imul        edx,dword ptr [i]  //乘法
00C6946E  mov         dword ptr [k],edx  


各个编译器前端就不一样就会导致错误,1,3;1,2的不同,不在于后者 。汇编只能说明该编译器的解释情况。当然通过汇编可以反过来理解编译器怎么解释i++的哈。
顶部