鱼C论坛

 找回密码
 立即注册
查看: 2826|回复: 4

++i的问题

[复制链接]
发表于 2019-2-16 22:07:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一个老问题了,但是还是有点不太懂
int i = 5,j=5,p,q;
p=(i++)+(i++)+(i++);  //括号内的i是同步加吗? 3个i++同时吗,如果3个括号同步算的话,结果应该是5+5+5,输入i=6,P=15。如果区分右侧优先级,应该是5 +6+7 ,最后输入I结果应该是8。P=18.

q=(++j)+(++j)+(++j);  //同上

输入 p q i j;

小白求助大神啦
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-2-16 22:14:31 | 显示全部楼层
右至左一个一个来。
而且要在下一条语句生效。

所以这里
p=(i++)+(i++)+(i++);  // 这条语句里虽然有多少i++ 但最后还是15.3*5
下新语句
temp=i //这时i也就是5 + 3 = 8,3个自增。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-16 22:39:35 | 显示全部楼层
p = (i ++) + (i ++) + (i ++)    ;
等效于
p = i + (i + 1) + (i + 2)       ;
i += 3                          ;
q = (++ j) + (++ j) + (++ j)    ;
等效于
q = (j + 1) + (j + 2) + (j + 3) ; 
j += 3                          ;

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-17 10:23:04 | 显示全部楼层
本帖最后由 行客 于 2019-2-17 10:51 编辑

首先声明一下,不同编译器下的处理结果可能是有不同的,这里以VC6下分析为例:

p=(i++)+(i++)+(i++);
执行完当前语句后,
在VC6下,首先很确定的告诉你p的值为15。从汇编代码我们先看下分析:
10:       p=(i++)+(i++)+(i++);  //括号内的i是同步加吗? 3个i++同时吗,如果3个括号同步算的话,结果应该是5+5+5,输入i=6,P=15。如果区分右侧优先级,应该是5 +6+7 ,最后输入I结果应该是8。P=18.
0040D796   mov         eax,dword ptr [ebp-4]                                ;dword ptr [ebp-4]即为局部变量i,这里将i的值传送到eax
0040D799   add         eax,dword ptr [ebp-4]                                ;将eax和i相加,并将结果放到eax
0040D79C   add         eax,dword ptr [ebp-4]                                ;将eax和i再次相加,并将结果放到eax
0040D79F   mov         dword ptr [ebp-0Ch],eax                        ;将eax的值传送到dword ptr [ebp-0Ch],即p。此时i没有变化,依然为5,p的结果为5。
0040D7A2   mov         ecx,dword ptr [ebp-4]                                ;以下开始计算i的变化:将dword ptr [ebp-4]即为局部变量i的值传送到ecx
0040D7A5   add         ecx,1                                                        ;将ecx的值加1
0040D7A8   mov         dword ptr [ebp-4],ecx                                ;以下相同
0040D7AB   mov         edx,dword ptr [ebp-4]
0040D7AE   add         edx,1
0040D7B1   mov         dword ptr [ebp-4],edx
0040D7B4   mov         eax,dword ptr [ebp-4]
0040D7B7   add         eax,1
0040D7BA   mov         dword ptr [ebp-4],eax                                ;最终将计算后的eax传值给dword ptr [ebp-4],即i。i值此时为8
通过以上汇编代码分析,我们可以很清楚的看到:i++的后加加,是在执行完其他运算并赋值给p后,再做的后自增变化。
这里也印证了:后加加,就是先用这个变量,然后再用这个变量做自增。

那么,
q=(++j)+(++j)+(++j);
就很好理解了。应该是先自增完,再计算呗。
也就印证了:前加加,就是先加,然后才用这个变量。这个理解,应该是正常的、标准的理解。
但是,但是,但是还真有点变化。。。VC6下q的值的结果竟然为,22!这到底为什么
为了便于理解,还是先看下汇编代码:
12:       q=(++j)+(++j)+(++j);  //同上
0040D7BD   mov         ecx,dword ptr [ebp-8]                                ;dword ptr [ebp-8]即变量j
0040D7C0   add         ecx,1                                                         ;我们清楚的看到,是先增1,j结果为6
0040D7C3   mov         dword ptr [ebp-8],ecx
0040D7C6   mov         edx,dword ptr [ebp-8]
0040D7C9   add         edx,1                                                         ;我们清楚的看到,再增1,j结果为7
0040D7CC   mov         dword ptr [ebp-8],edx                                
0040D7CF   mov         eax,dword ptr [ebp-8]
0040D7D2   add         eax,dword ptr [ebp-8]                                ;但是这里很奇怪,开始计算j+j了,这时eax为14。
0040D7D5   mov         ecx,dword ptr [ebp-8]                                ;这里开始又将j传值给ecx
0040D7D8   add         ecx,1                                                        ;ecx自增1
0040D7DB   mov         dword ptr [ebp-8],ecx                                ;ecx传递给j,j的值变成8了。
0040D7DE   add         eax,dword ptr [ebp-8]                                ;计算eax的14加j的8,结果22传给eax。
0040D7E1   mov         dword ptr [ebp-10h],eax                        ;最终q的值为22。
j的值运算结束后为8好理解,这个没什么理解方面的问题。但是q的值为什么会这么特殊,这样计算?
原因是:不同的编译器,生产的代码不一样,导致的结果也会不一样。或者说,这种计算结果,只单纯从C的角度去思考根本就想不明白,是因为这个根本就没有什么道理和标准,甚至对于编译器来讲,或许这就算是一个BUG。所以,我一直不建议搞什么特别长的、连续使用的复杂的++或者--,你自己写程序为的是一个正确的运行结果,非要把程序写的自己都难以理解有意义吗?
当年我们很多的教科书中,在这个地方来回的折腾,来回的讲,搞的大家晕晕乎乎,其实一点价值都没有。所有,有某教授的C语言教材,一直被人吐槽。

为了说明不同编译器下,结果会不一样,我们可以再继续做以下测试:
我们简化代码为:
#include <stdio.h>
void main()
{
int j = 5;
int q;
q =(++j)+(++j)+(++j);
}

环境:win7

编译器:GCC

IDE:vc++6.0  /DEV-C++

结果:q = 22
6:    q =(++j)+(++j)+(++j);
00401036   mov         eax,dword ptr [ebp-8]           移动J=5到寄存器eax内
00401039   add         eax,1                                       在寄存器eax值上加1,eax=6
0040103C   mov         dword ptr [ebp-8],eax          把寄存器的值移动到变量j上去,j= 6
0040103F   mov         ecx,dword ptr [ebp-8]           移动J=6到寄存器ecx
00401042   add         ecx,1                                       在寄存器上ecx+1,j=6
00401045   mov         dword ptr [ebp-8],ecx          把寄存器ecx上的值移到J上去,J=7
00401048   mov         edx,dword ptr [ebp-8]         把J=7移动到寄存器edx=7
0040104B   add         edx,dword ptr [ebp-8]          edx值+j  此时j=7,edx=7+7
0040104E   mov         eax,dword ptr [ebp-8]          把j=7Move给 第一个寄存器eax
00401051   add         eax,1                                       eax再加1,此时寄存器eax=8
00401054   mov         dword ptr [ebp-8],eax          把此时的eax的值move给 j=8
00401057   add         edx,dword ptr [ebp-8]           edx值= edx+j = 14+8
0040105A   mov         dword ptr [ebp-0Ch],edx      edx值 move给 j = 22



环境:win7

编译器:GCC

IDE: VC++ 2008

运行结果:24
q =(++j)+(++j)+(++j);
003A1815  mov         eax,dword ptr [j]   //eax = 5,j = 5
003A1818  add         eax,1   //eax = 6
003A181B  mov         dword ptr [j],eax  j = 6 
003A181E  mov         ecx,dword ptr [j]  ecx = 6
003A1821  add         ecx,1  ecx = 7
003A1824  mov         dword ptr [j],ecx  j = 7 
003A1827  mov         edx,dword ptr [j]   edx = 7
003A182A  add         edx,1   edx = 8
003A182D  mov         dword ptr [j],edx   j = 8 
003A1830  mov         eax,dword ptr [j] eax = 8
003A1833  add         eax,dword ptr [j] eax = 16
003A1836  add         eax,dword ptr [j]  eax = 24
003A1839  mov         dword ptr [q],eax

评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
wjp + 1 + 1 学到了

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-17 10:53:58 | 显示全部楼层
有疑问请继续跟帖。无疑问请选为最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-3 08:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表