我的第一份工作是C语言的嵌入式软件开发,公司内部有严格的C语言编程规范,因此并没被此类问题烦恼过。

对于i++和++i的问题,规范规定使用++i的形式。因为这样不需要保存初始值,可以节省一条汇编指令。所以我一直都是用下面的方式:

for (int i = 0; i < 100; ++i)

其实这样写没有i++顺手,经常敲错还要回去改。

至于节省了哪条指令,今天我动手实验了一下,发现编译器其实可以发现i的初始值有没有被人使用,否则就不会保存那个临时变量。

enter image description here

以上代码经过编译会变成下面的汇编指令,可以看出.L3的地方有个100次的循环,换成使用i++的方式后,编译出来的汇编指令也是完全一样。

enter image description here

所以对于内置数据类型,++i和i++几乎是没有区别的。(对于类对象,例如STL里面的迭代器(iterator),尤其是自己开发的类型,重载这两个操作符的性能可能会有不同,不过在强大的编译器面前,好像凡事没有绝对。)

本来事情也许到这里就结束了,但见证奇怪的时刻即将到来。我原本打算想用苹果系统截个漂亮一点的图,但发现Apple编译器的结果却是这样的!

enter image description here

我能不能说一句粗话,“简直亮瞎了我的钛合金狗眼啊”。您老人家就这样直接返回5050啦!

结论:

  1. 编译器功能太强大,想搞砸都不行了!

  2. But, you can do something does not mean that you should do it.

注:以上结果分别在Ubuntu和OS X上使用gcc -std=c99 -O2 -S *.c命令进行O2级优化编译。Ubuntu gcc 4.8.2,Apple LLVM version 6.1.0