for(i = 0; i< 10000000000; ++ i)编译成无限循环?

时间:2014-01-19 14:18:52

标签: c assembly for-loop

我正在运行一些测试,看看++ i和i ++是如何转换为asm的。我写了一个简单的:

int main()
{
    int i;
    for(i=0;i<1000000;++i);
    return 0;
}  

使用 gcc test.c -O0 -o test 编译它,并使用 objdump -d test 检查asm:

4004ed: 48 89 e5                mov    %rsp,%rbp
4004f0: c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)  // i=0;
4004f7: eb 04                   jmp    4004fd <main+0x11>
4004f9: 83 45 fc 01             addl   $0x1,-0x4(%rbp)     // ++i;
4004fd: 81 7d fc 3f 42 0f 00    cmpl   $0xf423f,-0x4(%rbp) // 
400504: 7e f3                   jle    4004f9 <main+0xd>   //i<1000000;
400506: b8 00 00 00 00          mov    $0x0,%eax
40050b: 5d                      pop    %rbp
40050c: c3                      retq 
到目前为止一切顺利。奇怪的事情(如果我理解asm代码正确)是当而不是我&lt; 1000000我写了i&lt; 10000000000。对于具有停止条件的循环完全相同i <10000000000转换为以下汇编代码:

4004ed: 48 89 e5                mov    %rsp,%rbp
4004f0: c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
4004f7: 83 45 fc 01             addl   $0x1,-0x4(%rbp)
4004fb: eb fa                   jmp    4004f7 <main+0xb>

根据我的理解,这是无限循环,因为生成的完全相同:

 for(i=0;;++i);

问题是,它是否真的可能被编译为无限循环?为什么? 我正在使用Ubuntu 13.04,x86_64。

感谢。

6 个答案:

答案 0 :(得分:17)

这是因为您的体系结构中int的最大值永远不会达到10000000000.它会在达到该值之前的某个时刻溢出。因此,条件i < 10000000000将始终评估为真,这意味着这是一个无限循环。

编译器能够在编译时减去这个,这就是它为无限循环生成适当的程序集的原因。

编译器可以向您发出警告。为此,您可以使用以下命令启用“额外”警告级别:

gcc -Wextra
例如,GCC 4.8.2会告诉你:

warning: comparison is always true due to limited range of data type [-Wtype-limits]
for (i = 0; i < 10000000000; ++i);
^

它甚至会告诉您具体控制此类警告的警告选项(Wtype-limits)。

答案 1 :(得分:5)

整数范围是:-2,147,483,648到2,147,483,647

你就像在它之上。

答案 2 :(得分:4)

如果10000000000超出了int的范围,但是在long或long long的范围内,对于你的编译器,那么i&lt;在进行比较之前,10000000000将我投入很长或很长时间。

实现它总是假的,编译器然后删除冗余比较。

我希望有一些编译器警告。

答案 3 :(得分:2)

这是因为您使用int来存储这么大的号码 结果,i wraps围绕着它自己,并且永远不会达到for循环的终止条件 当你超过C / C ++中数据类型的限制时,可能会发生有趣的事情 编译器可以在编译时检测这些东西,因此,用汇编语言生成无限循环的代码。

答案 4 :(得分:2)

问题是:  你不能在&#34; i&#34;。

中存储这么大的号码

查看https://en.wikipedia.org/wiki/Integer_%28computer_science%29了解更多信息。

&#34; I&#34; (变量)不能达到10000000000,因此循环总是计算为true并且运行无限次。

您可以为i使用较小的数字或其他容器,例如Boost的multiprecision库: http://www.boost.org/doc/libs/1_53_0/libs/multiprecision/doc/html/boost_multiprecision/intro.html

答案 5 :(得分:2)

这是因为编译器发现您使用的条件永远不会为false,因此根本不会对条件进行求值。

int永远不能保存与10000000000一样大的值,因此值始终低于true。当变量达到其最大值并且您尝试进一步增加它时,它将环绕并从其最低可能值开始。

如果您使用文字值for (i = 0; true; ++i);

,则会发生同样的情况删除
true

编译器只是使它成为没有条件的循环,它实际上不会在每次迭代时评估{{1}}值以查看它是否仍为真。