i++ , ++i 的区别

本文详细解析C++中++运算符的优先级规则,并通过汇编代码展示其实际运行效果。同时,对比了迭代器前置++与后置++在效率上的差异,提供代码优化建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

困惑新手的++(--)运算符,很多老师都会这么说,++在前就先加后运算 ,++在后就先运算,再自增1,

国内大学C接触的也多半是谭XX教授编写的(反正当时我们是这样的),在书里经常搞来搞去,搞一堆运算式放在一起,非得你记起来他们的优先级,清楚他们的与语法才能知道结果。对于我这种不太死记硬背的人来说,我觉得还是写一些明确的表达式会让看的人心里比较舒畅一点,比如该加括号就加括号,该拆分就拆分。

废话不多说,看下面代码,代码很简单,有点基础一看就知道结果,不过这不重要,想要弄清楚到底是怎么运算的,很简单,反汇编即可:

代码及反汇编代码:

#include <stdio.h>

int main()
{
	int i = 1;
0132138E  mov         dword ptr [i],1 
	int j = 1;
01321395  mov         dword ptr [j],1 
	
	i++;
0132139C  mov         eax,dword ptr [i] 
0132139F  add         eax,1 
013213A2  mov         dword ptr [i],eax  // i = i + 1
	++i;
013213A5  mov         eax,dword ptr [i] 
013213A8  add         eax,1 
013213AB  mov         dword ptr [i],eax  // i = i + 1, 可见,单独的i++, ++i是一样的。
	j = j + i++;
013213AE  mov         eax,dword ptr [j] 
013213B1  add         eax,dword ptr [i] 
013213B4  mov         dword ptr [j],eax  // j = i + j;
013213B7  mov         ecx,dword ptr [i] 
013213BA  add         ecx,1 
013213BD  mov         dword ptr [i],ecx  // 然后 i = i + 1
	j = j + ++i;
013213C0  mov         eax,dword ptr [i] 
013213C3  add         eax,1 
013213C6  mov         dword ptr [i],eax  // i = i + 1
013213C9  mov         ecx,dword ptr [j] 
013213CC  add         ecx,dword ptr [i] 
013213CF  mov         dword ptr [j],ecx  // 然后 j = j + i
	j = j + i++ + i++;
013213D2  mov         eax,dword ptr [j] 
013213D5  add         eax,dword ptr [i] 
013213D8  add         eax,dword ptr [i] 
013213DB  mov         dword ptr [j],eax // j = j + i + i
013213DE  mov         ecx,dword ptr [i] 
013213E1  add         ecx,1 
013213E4  mov         dword ptr [i],ecx // 然后 i = i + 1
013213E7  mov         edx,dword ptr [i] 
013213EA  add         edx,1 
013213ED  mov         dword ptr [i],edx // 再次 i = i + 1 
	j = j + ++i + ++i;
013213F0  mov         eax,dword ptr [i] 
013213F3  add         eax,1 
013213F6  mov         dword ptr [i],eax // i = i + 1
013213F9  mov         ecx,dword ptr [i] 
013213FC  add         ecx,1 
013213FF  mov         dword ptr [i],ecx // 再次 i = i + 1
01321402  mov         edx,dword ptr [j] 
01321405  add         edx,dword ptr [i] 
01321408  add         edx,dword ptr [i] 
0132140B  mov         dword ptr [j],edx // 然后 j = j + i + i
	return 0;
0132140E  xor         eax,eax 
}

根据以上的代码注释,显然,单独的 i++ , ++i 是一样的,当在一个复杂的表达式里,则表现不太一样。而且一个表达式里多次出现i++或者++i的时候,也可以根据上面的规律拆分。

虽然我们可以根据运算符的优先级来推测结果,但是能一目了然的代码为什么不写呢?所以建议大家,i++ 或者++i应该单独写,不要写在复杂表达式里。让人有想砍你的冲动。

例如  

j = j + i++;

写成 

i++;

j = j + i;

或者

i++;

j += i;

以上发汇编结果是在VS中测试的,C/C++在这个问题上,是由编译器决定的,这段汇编是经过编译器优化的结果,然而像在java 或者C#中,++问题是用语言来规定规则的,所以在java/C#中,涉及++的运算结果是可以确定的,但是C/C++的编译器有很多种,不保证每一种编译器优化的结果都是一致。


隔了一年,我再回来看到这个自己写的东西,有必要更新一下。因为上面这种情况是对于一个整形变量的运算,所以说法还算成立,但是最近自己研究STL源代码的时候,发现上面的说法用在迭代器中并不适用。

来看一看SGI STL中list的迭代器的++重载:

//前置++  
_Self& operator++() { 
    this->_M_incr();
    return *this;
  }
//后置++,括号中加了一个int,表示这是后置++,并没有其他的意思
  _Self operator++(int) { 
    _Self __tmp = *this;
    this->_M_incr();
    return __tmp;
  }
明显可以看到。后置++中需要分配一个临时变量来保存当前的这个迭代器所包装的数据。然后像前置++一样,调用了相同的递增函数。。然后返回保存下来的数据的迭代。

那么当我们对迭代器单独使用++的时候,放在前和放在后,是不一样的。为了效率更高。当然选择前置++ 。

如下:

//第一种
list<int>::iterator it = xx.begin();
for (; it != xx.end(); ++it)
{

}

//第二种
list<int>::iterator it = xx.begin();
for (; it != xx.end(); it++)
{

}

显然第一种效率会高一些。如果数据量很大。循环次数较多的时候。第一种就会比第二种明显快一些。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值