2016-09-05 11 views
20

我嘗試使用windbg在進入成員函數時打印「this」指針,如下所示。爲什麼VS和Windbg即使在調試版本中也將「this」指針打印爲「0xcccccccc」?

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調試版本(32位)編譯它

(2)我設置 「大一」 功能的破發點。 (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 

這是爲什麼?該程序運行良好,調試版本不優化任何東西,似乎一切都很好。但爲什麼「這個」指針是無效的?

我用VC自己的IDE來調試,同樣的觀察。但爲什麼?

+4

'這個'沒有在'Doit'函數中定義:它不是您的任何類的成員。 –

+2

如果您將'return 1'放在另一行上,您將在那裏看到一個有效的'this'。 – rustyx

+0

就像RustyX說的那樣,除非函數調用堆棧,否則不能進入單行函數。至少不適用於Visual Studio。將聲明放在單獨的行上。 – UmNyobe

回答

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

這是您的代碼風格導致此問題。由於您將函數體與函數定義寫在同一行,因此斷點將設置在函數的開頭,而不是函數體的開頭。此時該函數的序言尚未執行。設置堆棧幀並檢索函數參數的代碼。隱藏的這個參數就是其中之一,它作爲函數的第一個參數傳遞。

您只能觀察到這個在該序言代碼執行之後具有適當的值。這需要使用Debug> Windows> Disassembly,以便在mov dword ptr [this],ecx之後您可以跨越序言代碼,一直到指令。非常尷尬。

你不會有這個問題時,寫這樣的:

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

或者任何護具風格你喜歡。現在設置斷點確保函數的序言被執行並且這個具有期望值。

或者通過知道單步執行函數來解決這個問題並不有趣,因爲它沒有做任何值得調試的事情。你這樣寫的基本原因。改用Debug> Step Over來代替。如果你不小心踩到了這樣的功能,那麼使用Debug> Step Out快速回到你實際想要調試的代碼中。

+13

這很搞笑。 :) –

+0

但是,爲什麼不「進入」進入FuncOne並停止'返回1;'? – rustyx

+8

調試信息是基於行號的。 VS支持的其他語言也可以考慮列號。由於預處理器的原因,這在C和C++中被破壞了,編譯器只能在代碼被破壞後看到代碼。哦,那個惡毒的預處理器。不是那個有趣的btw。 –

相關問題