在不应该执行时执行break

时间:2012-08-03 09:42:24

标签: c++ if-statement for-loop break

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。

有人可以向我解释这种奇怪的行为吗?

3 个答案:

答案 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次。 See the code