VS と Windbg がデバッグ バージョンでも「this」ポインタを「0xcccccccc」と印刷するのはなぜですか? 質問する

VS と Windbg がデバッグ バージョンでも「this」ポインタを「0xcccccccc」と印刷するのはなぜですか? 質問する

以下のように、メンバー関数に入るときに windbg を使用して「this」ポインターを印刷しようとしました。

class IBase {
    int m_i;
public:
    IBase() :m_i(23) {}
    virtual int FuncOne(void) = 0;
    virtual int FuncTwo(void) = 0;
};
class DerivedOne : public IBase {
public:
    virtual int FuncOne(void) { return 1; };//set break point here.
    virtual int FuncTwo(void) { return 2; };
};
class DerivedTwo : public IBase {
public:
    virtual int FuncOne(void) { return 101; };
    virtual int FuncTwo(void) { return 102; };
};
void DoIt(IBase* Base)
{
    int i=Base->FuncOne();//break point here
}
int main(int argc, char *argv[])
{
    DerivedOne d1;
    DerivedTwo d2;
    DoIt(&d1);
    DoIt(&d2);
    return 0;
}

(1)VC2015デバッグ版(32bit)でコンパイルした

(2)「DoIt」関数にブレークポイントを設定します。

(3) Base->FuncOne() を押した時に、「F11」を押して DerivedOne の関数に入りました。

コールスタックは次のようになっていることがわかります。

0:000> k
 # ChildEBP RetAddr  
00 0041f654 0022157c ConsoleApplication1!DerivedOne::FuncOne [d:\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1.cpp @ 13]
01 0041f734 0022173c ConsoleApplication1!DoIt+0x2c [d:\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1.cpp @ 23]
02 0041f850 00221dc9 ConsoleApplication1!main+0x7c [d:\documents\visual studio 2013\projects\consoleapplication1\consoleapplication1.cpp @ 36]
03 0041f8a0 00221fbd ConsoleApplication1!__tmainCRTStartup+0x199 [f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c @ 626]
04 0041f8a8 75b9338a ConsoleApplication1!mainCRTStartup+0xd [f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c @ 466]
05 0041f8b4 77529902 kernel32!BaseThreadInitThunk+0xe
06 0041f8f4 775298d5 ntdll!__RtlUserThreadStart+0x70
07 0041f90c 00000000 ntdll!_RtlUserThreadStart+0x1b

しかし、「dv」コマンドは予期しない結果をもたらした

0:000> dv
       this = 0xcccccccc

なぜでしょうか? プログラムは正常に動作し、デバッグ バージョンでは何も最適化されず、すべてが正常であるように見えます。しかし、なぜ「this」ポインターが無効なのでしょうか?

VC 独自の IDE を使用してデバッグしましたが、同じ結果になりました。しかし、なぜでしょうか?

ベストアンサー1

virtual int FuncOne(void) { return 1; };//set break point here.

この問題の原因はコーディングスタイルです。関数本体を関数定義と同じ行に記述したため、ブレークポイントは関数本体の開始ではなく関数の開始に設定されています。その時点では、関数のプロローグはまだ実行されていません。スタックフレームを設定し、関数の引数を取得するコード。隠れたこれ引数はその 1 つであり、関数の最初の引数として渡されます。

観察することしかできないこれプロローグ コードが実行された後に適切な値を持つ。そのためには、デバッグ > ウィンドウ > 逆アセンブリを使用して、プロローグ コードを過ぎて、後の命令まで進む必要がありますmov dword ptr [this],ecx。非常に扱いにくいです。

次のように記述すると、この問題は発生しません。

virtual int FuncOne(void)
{ return 1; };//set break point here.

または、好みの括弧スタイル。ブレークポイントを設定すると、関数のプロローグが実行され、これ期待値を持ちます。

または、関数をステップ実行してもデバッグする価値のあることは何も行われないので、関数をステップ実行しても面白くないということを理解して対処します。これが、そのように記述した基本的な理由です。代わりに、[デバッグ] > [ステップ オーバー] を使用します。誤ってそのような関数にステップ インした場合は、[デバッグ] > [ステップ アウト] を使用して、実際にデバッグするコードにすばやく戻ります。

おすすめ記事