2
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;;
}

この後 - ブレークの後の 2 番目のセミコロンに注意してください - i は予想どおり 50 です。

誰かが私にこの奇妙な振る舞いを説明してもらえますか?

4

3 に答える 3

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 を使用しました。

于 2012-08-03T10:46:30.807 に答える
3

このコードは、無効な C++ ( ) であるため、適合するコンパイラではコンパイルできませんvoid main

そうは言っても、結果の値iは無関係です。コンパイラは、必要なことを何でも行うことができます。

その理由は、iがループの外で読み取られることはなく (それ自体は効果がないことが証明されています)、宣言されていないvolatileため、コンパイラは の値に関係なく、観察可能な副作用がないことを自明に証明できますi

于 2012-08-03T10:36:12.730 に答える
2

MSVC10 では、これは再現可能です。分解チェックしました。pdbファイルの生成に問題があるようです。ループの先頭に戻るジャンプ命令が次のソース行に混ざっている、それだけです。次の行へのステップを押すと、return ステートメントから for ループの先頭に戻り、期待どおりに 50 回ループを実行します。 コードを見る.

于 2012-08-03T11:10:34.257 に答える