Linux gcc for 循环中 i=i++ 会造成死循环问题及 ++i / i++ 汇编分析
2014-12-31 00:14
435 查看
在把 Windows 程序移植到 Linux 时遇到了死循环,最后定位到了类似这种的语句 for (i = 0; i < 1; i = i++),
别问我是谁写的,为什么这么写(泪目!)。
根据自己的感觉(感谢
mayjojo 纠正,C标准中 i=i++ 的行为未定义), i = i++ 应该等价于 i++, Windows 上确实是这样,但 Linux 不是,这应该是编译器差异造成的。
--------------------------------------- 可 i 的分割线 No.0 -----------------------------------------------------------------------------------------------
那么问题来了,为什么会这样呢?
用 arm-linux-gcc -S i.c 汇编一下,编译结果和源码如下(gcc 汇编的代码不太好看,所以用了 arm 版的):
首先介绍一下出现的汇编指令:
mov r3, #0 (把常数值赋值给 r3,相当于 r3=0)
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,为了移植性,不能相信编译器。
别问我是谁写的,为什么这么写(泪目!)。
根据自己的感觉(感谢
mayjojo 纠正,C标准中 i=i++ 的行为未定义), i = i++ 应该等价于 i++, Windows 上确实是这样,但 Linux 不是,这应该是编译器差异造成的。
--------------------------------------- 可 i 的分割线 No.0 -----------------------------------------------------------------------------------------------
那么问题来了,为什么会这样呢?
用 arm-linux-gcc -S i.c 汇编一下,编译结果和源码如下(gcc 汇编的代码不太好看,所以用了 arm 版的):
首先介绍一下出现的汇编指令:
mov r3, #0 (把常数值赋值给 r3,相当于 r3=0)
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,为了移植性,不能相信编译器。
相关文章推荐
- Linux gcc for 循环中 i=i++ 会造成死循环问题及 ++i / i++ 汇编分析
- 关于linux下 gcc 编译时for循环的报错。c99
- linux gcc汇编的问题
- Linux用GCC和GDB对C语言进行汇编语言分析
- 解决 Zend Studio For Linux 乱码和UBUNTU下不显示(白屏)问题
- 批处理问题:SET 命令在 FOR 循环中失效 / SET 环境变量生存域/作用域
- js中for循环的问题
- 深入浅出 分析Linux系统内核漏洞问题
- ARM SDT下的汇编移植到gcc for arm
- Linux下gcc编译中关于头文件与库文件搜索路径相关问题
- Linux内核2.6.14源码分析-双向循环链表代码分析
- linux汇编 常见问题 (zz)
- Linux和Windows区别分析之线程问题
- 关于Linux GCC的路径问题(Include路径, lib 路径)
- 解决安装Domino for Linux时配置的Web服务器无法启动的问题
- rootkit for linux 7.大杀器---反汇编引擎xde
- install gcc for ubuntu linux
- svchost.exe造成CPU使用率占用100%的常见问题分析
- 关于在DELPHI中FOR循环语句的使用问题
- 第六课 小数点代码分析及For循环语句