int main(int argc, char *argv[]) {
int i = 0;
for (i = 0; i < 50; i++)
if (false) break;
}
使用VS 2010进行编译和执行(VS 2008中的相同问题)。我在最后一行(结束括号)放了一个断点,然后通过调试器查看变量i。这段代码将i留在0.为什么?
int main(int argc, char *argv[]) {
int i = 0;
for (i = 0; i < 50; i++)
if (false) break;;
}
在此之后 - 请注意休息后的第二个分号 - 我是预期的50。
有人可以向我解释这种奇怪的行为吗?
答案 0 :(得分:3)
此代码不能在符合标准的编译器上编译,因为它是无效的C ++(void main
)。
也就是说,i
的结果值是无关紧要的:编译器可以做任何想做的事。
原因是i
永远不会在循环之外读取(它本身可以证明没有效果)并且没有声明volatile
因此编译器很容易证明没有可观察到的副作用,无论i
的价值如何。
答案 1 :(得分:3)
使用objdump -d -S
查看生成的汇编代码,我们可以看到GDB跳过循环的可能原因:
0000000000400584 <main>:
int main()
{
400584: 55 push %rbp
400585: 48 89 e5 mov %rsp,%rbp
volatile int i;
for (i = 0; i < 5; i++)
400588: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
40058f: eb 09 jmp 40059a <main+0x16>
400591: 8b 45 fc mov -0x4(%rbp),%eax
400594: 83 c0 01 add $0x1,%eax
400597: 89 45 fc mov %eax,-0x4(%rbp)
40059a: 8b 45 fc mov -0x4(%rbp),%eax
40059d: 83 f8 04 cmp $0x4,%eax
4005a0: 0f 9e c0 setle %al
4005a3: 84 c0 test %al,%al
4005a5: 75 ea jne 400591 <main+0xd>
4005a7: b8 00 00 00 00 mov $0x0,%eax
if (false)
break;
}
4005ac: c9 leaveq
4005ad: c3 retq
4005ae: 90 nop
4005af: 90 nop
即使编译时关闭了优化(-O0
标记为g ++),实际上也没有为循环体生成代码。这可能意味着GDB会将循环视为单个语句,并且不会正确地循环循环。
我使用的是GCC版本4.4.5和GDB版本7.0.1。
答案 2 :(得分:2)
在MSVC10中,这是可重现的。我检查了拆卸。这似乎是pdb文件生成中的一个问题。回到循环开头的跳转指令与下一个源行混合,就是这样。 如果按步骤到下一行,它将从return语句返回到for循环的开头,并按预期执行循环50次。 。