先加后加,孰优孰劣? —— ++i 和 i++ 比较

先加后加,

孰优孰劣?

—— ++i 和 i++ 比较

8f1ddd2baab5cc7896adeef3e3f3b007.png

熟悉C语言或者C++语言的人都知道,运算符中有个++和--的操作,既可以放到变量前面,也可以放到变量后面,而且在绝大部分情况下,两者的结果是一样的。那么它们到底是不是完全一样呢?如果不一样的话,具体在什么方面会不一样呢?本文以++为例,但结论同样适用于--操作。

PART 01

对 i 值的影响

首先,前++和后++在任何情况下,对i的运行结果都是一样的。比如,设 int i=5,那么下列两行代码执行后,i 的值都是6:

++i;
i++;

以上两个操作都等价于 i = i+1。

PART 02

返回值

300ccdc057d2b6d705cb16691c5472a4.png

______

++ --

8dc71f8cbfa85d386acd285589021e73.png

我们知道,赋值操作是可以形成一个链的,也即你可以这样写:

a = b = c + 1;

执行的时候,是先执行b = c +1,再把执行的结果赋给 a。也就是说赋值操作是有返回值的。

++i 和 i++ 是特殊的赋值语句,所以也是有返回值的。跟其它赋值语句一样,它们既可以作为独立的一行执行,也可以作为表达式的一部分(算术表达式或者逻辑表达式)。当作为独立的一行执行时,它们的返回值是被丢弃掉的。当放在表达式里时,它们的返回值是有用的,要参与运算。

现在,本质的区别来了。++i的返回值,是返回加1以后的i,而 i++ 是返回加1之前的i。比如,假设现在 i 等于5,那么在执行下面两行代码后(不是先执行第一行,再执行第二行,是指两行分开来独立执行),a 和 b 的值是不一样的:

a = ++i;
b = i++;

a 的值是6,b 的值是5。

这个其实是很好记的,放在前面就是先加1(后返回),放在后面就是(先返回)后加1。

但是,当把这两个表达式放在判断条件里时,就要特别当心,即使是相当资深的程序员有时也会犯错。

我们来看个例子:

int i = -1;
char s[27];
s[26] = 0;
while(i++<25)
  s[i] = i + ‘A’;
puts(s);

当这段代码执行完毕后,如果你不再使用 i 了,那没关系。如果你还想继续使用 i,那么就要好好考虑 i 现在的值了。一般人会认为,i等于25时,循环的判断结果为假,循环退出,所以现在 i 的值就是25。但是,再思考一下,i++ 是先返回再加1 的,这个加1的动作跟判断的结果为真还是为假没有关系(只有循环体里的执行语句才会受到判断结果的影响),只要判断这个动作发生了,i 加1就一定会发生,所以现在 i 的值是26。这几乎有点颠覆你的认知了,但结果就是这样。

要避免误用 i 的值,最好在再次使用 i 前给 i 重新赋值。当然,最彻底的方法是,不要在条件判断里使用这种简写的方式。

(这种在判断条件里简写的方式还有一个缺点。由于 i 加1是在给数组赋值之前发生的,为了第一次循环是给第0个元素赋值,i 的初始值要设成-1,或者在给数组赋值前,把 i 先减1,两种做法都是很不直观的。)

PART 03

效率

如果你没有看过Scott Meyers的《More Effective C++》,那你一定不认为这两种写法会有效率上的差异,但不幸的是,两种方式的效率是有差异的。++i 要比 i++ 效率高,因为后者的内部实现调用了前者。大家知道,函数调用是要有开销的,多一次函数调用,效率就低一点。

abfa14ace4378647e0e210a64cae37f9.jpeg

More

Effective

C++

那么,为什么i++ 实现要调用++i呢?这就再次关系到这两个表达式的返回值。我们说i++ 是先返回 i 的值,然后再给 i 加1,实际代码中是没法先返回的,返回了函数就结束了,后面的操作不能被执行了。必须要把 i 的值先赋给另外一个变量,然后给 i 加1,然后再返回那个变量。i++ 的实现差不多是这样的:

int PostPlusPlus(int *i)
{
  int j = *i;
  ++(*i);
  return j;
}

由此你就明白了,为什么 ++i 要比 i++ 效率高。

PART 04

何去何从

那么在实际使用中,我们到底应该选择哪一个呢?答案是看场合。

如果是上层应用,而且不是在一个需要反复执行的循环里,那么两个都可以。因为现在硬件速度已经很快了,对于上层应用,根本不在乎这点效率的差别。

如果是在底层应用,或者在一个需要反复执行的循环里,那么就要考虑效率的问题。底层应用可能会被频繁地调用,即使一次调用只差十万分之一秒,多次反复调用就会有明显的差别。

如果是在条件判断表达式里,那么,还是不要用吧,除非你有十足的把握能够驾驭它。

总结:前++和后++,看起来很像,但还是有些细微的差别。明白了这些差别,当代码出错时,你就知道是怎么造成的了。

本文的结论同样适用于前--和后--。

如果你要了解更深入的分析,建议你看下Scott Meyers的《More Effective C++》,里边有更精彩的内容,比如谈到了++++的情形。

好了,今天的分享就到这里。大家一起来学编程,每天进步一点点!

i++

45a70bd9bb956d09cb7b2ab022cc2957.png

【盛格塾】

正心诚意,格物致知

人文情怀审视软件,以软件技术改变人生

177be8ef269257c8500f3ca22bf9a94b.png

格友公众号

91ed10717258458fbca8765c0045b167.png

盛格塾小程序

扫描上方二维码或在微信中搜索“盛格塾”小程序

可以阅读更多文章和有声读物

往期推荐

代码为王,杜绝空谈 ——创客少年C语言培训班2024春季班如期开讲

幽兰满庭开,清香随风来——格蠹科技的幽兰本大揭秘

雏鹰展翅——创客少年C语言编程2024春季班即将开讲

龙年开春,格蠹有礼——极客少年编程套餐疯狂来袭

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值