23

编程小知识之 自增(自减)运算符

 3 years ago
source link: https://blog.csdn.net/tkokof1/article/details/102795683
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

编程小知识之 自增(自减)运算符

tkokof1 2019-10-29 11:04:28 276

本文讲述了 C/C++ 中 自增(自减)运算符 的一些知识~

自增(自减)运算符应该是 C/C++ 编程中的基础知识了,而自增(自减)运算符又有两种形式,分别是 前置自增(自减)后置自增(自减) (出于简单考虑,后文仅以自增运算符进行举例讲解).

譬如表达式 ++i 和 i++ 就分别表示对 i 进行前置自增 和 对 i 进行后置自增,用代码来说明的话, ++i(前置自增) 大概和以下代码等价:

i = i + 1;
return i;

而 i++(后置自增) 则大概和以下代码等价:

v = i;
i = i + 1;
return v;

可以看到, ++i 和 i++ 虽然都对 i 进行了增 1 操作,但是 ++i 返回了自身,而 i++ 返回了一个临时变量(用以保存 i 之前的数值),所以 i++ 比 ++i 要消耗更多的 CPU 资源(因为要使用临时变量),所以自己编码时也慢慢形成了一个习惯: 多用前置自增,少用后置自增.

虽然就现在的程序开发来讲,似乎我们已经不必特别关心 前置自增 和 后置自增 的效率差异了,在合适的情况下,编译器对于 前置自增 和 后置自增 也能生成同样高效的汇编代码了,但是自己依然坚持着上面的编码习惯(多用前置自增,少用后置自增),理由也很简单:虽然 前置自增 和 后置自增 的效率相仿甚至相同,但是 前置自增 仍然在理论上要优于 后置自增.

(下面的示意图是 for 循环中 前置自增 和 后置自增 编译器(MSVC)对应生成的汇编代码,可以看到,两者对应生成的汇编代码是一致的)

前置自增汇编码
后置自增汇编码

但后面从 Game Engine Architecture 中却了解到了一个有些颠覆的知识: 前置自增 效率上其实一般是要 慢于 后置自增 的 !!!

这里的原因是 前置自增 会比 后置自增 产生更多的 指令流水线停顿(stall),一般情况下,虽然 前置自增 对比 后置自增 会产生更少的指令操作,但是其产生的指令流水线停顿对效率的影响更大,所以我们应该: 多用后置自增,少用前置自增 !

自己初看到这个结论时自然是将信将疑,毕竟和自己之前的认知大相径庭,虽然我也认可书中给出的理由解释,但还是决定要亲自测试验证一下:

// pre-increment profile
int index = 0;
int value = 0;
for (int i = 0; i < count; ++i)
{
	value = ++index;
}

// post-increment profile
int index = 0;
int value = 0;
for (int i = 0; i < count; ++i)
{
	value = index++;
}

首先确定 前置自增 和 后置自增 确实生成了不同的汇编代码:

前置自增汇编码
后置自增汇编码

后面就是简单的测量运行时间了,结果也确实如书中所说:

后置自增 平均要比 前置自增 快 20% 左右 ~

多用后置自增,少用前置自增,虽然 后置自增 会产生更多的指令操作,但是一般情况下对指令流水线的影响更小,所以相比 前置自增 其实反而更加高效.

从一开始懵懂的编写 后置自增 代码,到后来了解了内部原理后改用 前置自增,再到现在了解了更多原理之后改回 后置自增,颇有些"返璞归真"的味道~


我在 C# 中也同样测试了一下 前置自增 和 后置自增 的效率差别,发现结论与之前是相反的:

前置自增 平均要比 后置自增 快 23% 左右 ~

看来在非 native 语言中还是应该优先选择 前置自增.

进一步总结

关于 前置自增 和 后置自增 的效率问题不能一概而论,不同语言可能产生迥异的效率差别, profile 可以帮助我们确定较优的自增方式~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK