每个C程序员都知道同一个for循环语句可以有两种写法:
A: for (i = 0; i < cnt; i++){ }
B: for (i = cnt; i > 0; i--){ }
前几天,DEBUG的时候, 发现采用A写法的代码反汇编出来有BUG.当时没有时间记录,环境也没有保存下来.今天尝试重现,又没来出现上次的问题...很奇怪.
很久很久以前也听说过这两种写法有区别,今天就顺便分析一下,也算没有白忙.
编译环境: mipsisa32-xlr-linux-gcc 3.4.3
测试代码见附件: raw_socket.c
A反汇编之后的代码如下:
B反汇编之后的代码如下:
对A的分析:
401158: 将 i 清零
40115c: 将 i 的值加载到寄存器 v0
401160: 将 cnt 的值加载到寄存器 v1
401164: 比较 v0 是否小于 v1 即 i 是否小于 cnt. 如果 i < cnt 则 v0 的值为 1 否则 v0 的值为 0
401168: 如果 v0 的值为 0 即 i > cnt, 则跳到 4011a8 地址执行, 即跳出 for 循环
...
4011a0: 跳到 40115c 重新开始 for 循环
4011a4: 把 v0 即 i 的值写入内存. 由于mips的流水行机制, 在上一条语句真正跳转前,这条语句会被执行
对B的分析:
401158: 将 cnt 的值加载到寄存器 v0
40115c: 将 v0 的值赋给 i, 即将 cnt 的值赋给 i
401160: 将 i 的值加载到寄存器 v0 (这一条有必要么?)
401164: 如果 v0 的值小于等于 0, 即 i <= 0, 则跳到 4011a4 处执行, 即跳出 for 循环
...
40119c: 跳到 401160 地址执行, 重新开始 for 循环
4011a0: 把 v0 即 i 的值写入内存.
通过上面的分析可以看出A要比B多一条语句: A的401160. 每次for循环, A都要从内存中多加载一次cnt的值.
内存的读取一般远远小于CPU的执行速度.A的效率应该不如B高.
将同样的代码,在x86上编译,反汇编.
系统: Fedora 17 x86
编译器: gcc 4.7.2
A写法的反汇编结果:
B写法的反汇编结果:
A写法同样多了对cnt内存的读取...