Linux gcc for 循环中 i=i++ 会形成死循环问题及 ++i / i++ 汇编分析

在把 Windows 程序移植到 Linux 时遇到了死循环,最后定位到了相似这种的语句 for (i = 0; i < 1; i = i++),linux

别问我是谁写的,为何这么写(泪目)。缓存

根据我本身的感受, i = i++ 应该等价于 i++(C标准中 i=i++ 的行为未定义), Windows 上确实是这样,但 Linux 不是,这应该是编译器差别形成的。spa

--------------------------------------- 可 i 的分割线 No.0 --------------------------------------------------------------
orm

那么问题来了,为何会这样呢?内存

用 arm-linux-gcc  -S  i.c 汇编一下,编译结果和源码以下(gcc 汇编的代码不太好看,因此用了 arm 版的):编译器


首先介绍一下出现的汇编指令:源码

mov r3, #0       (把常数值赋值给 r3,至关于 r3=0)it

str r3, [fp, #-8] (把 r3 的值存储到内存地址 [fp, #-8])编译

ldr r3, [fp, #-8] (把内存地址 [fp, #-8] 的值载入到 r3,和 str 相反)效率

add r2, r3, #1    (r2 = r3 + 1)

okey, 实际上是先把 i 的原始值缓存到 r3,而后加1的值赋给 r2,r2会更新 i 值(由于 i++), 最后 r3 也会更新 i 值(由于 i=),至于为什么是这个顺序,请呼叫大神吧。因此,i 的值会一直为0,致使文章开头的 for 循环就死了。

--------------------------------------- 可 i 的分割线 No.1 --------------------------------------------------------------

为了好理解,我还汇编出了 j=i++,以下:


j = i++ : 仍是先缓存 i 的原始值,而后把加1的 i 值赋给 i,最后在把缓存的 i 的原始值赋给 j(和 i = i++ 的顺序同样)。

j = ++i : 先更把加1的 i 值赋给 i,而后再取出 i 值赋给 j 。

--------------------------------------- 可 i 的分割线 No.2 --------------------------------------------------------------

此外,一直想看看i++ 和++i 的汇编有什么不一样,结果以下:


由于一直都听过这个说法,for 循环中 ++i 的效率比 i++ 高,但从上图中能够当作,在单独的语句中,

++i 和 i++ 是同样的(gcc 系列编译器),不过仍是推荐用 ++i,为了移植性,不能相信编译器。

相关文章
相关标签/搜索