为什么即使在调试版本中VS和Windbg也将"this"指针打印为"0xcccccccc"?

Tro*_*yvs 20 c++ pointers windbg this break

我尝试使用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;
}
Run Code Online (Sandbox Code Playgroud)

(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
Run Code Online (Sandbox Code Playgroud)

但是"dv"命令给出了意想不到的结果

0:000> dv
       this = 0xcccccccc
Run Code Online (Sandbox Code Playgroud)

为什么是这样?程序运行良好,调试版本没有优化任何东西,似乎一切都很好.但为什么"这个"指针无效?

我使用VC自己的IDE进行调试,同样的观察.但为什么?

Han*_*ant 41

virtual int FuncOne(void) { return 1; };//set break point here.
Run Code Online (Sandbox Code Playgroud)

这是您的编码风格导致此问题.由于您在与函数定义相同的行中编写了函数体,因此断点设置在函数的开头,而不是函数体的开头.此时,该功能的序言尚未执行.设置堆栈帧并检索函数参数的代码.隐藏的这个参数就是其中之一,它作为函数的第一个参数传递.

在执行序言代码之后,您只能观察具有正确值的值.这需要使用Debug> Windows> Disassembly,这样您就可以跳过序言代码,一直到指令之后mov dword ptr [this],ecx.很尴尬.

写这样的时候你不会遇到这个问题:

virtual int FuncOne(void)
{ return 1; };//set break point here.
Run Code Online (Sandbox Code Playgroud)

或者你喜欢的任何支撑样式.现在设置断点确保函数的序幕被执行,有预期值.

或者通过了解踩踏函数并不感兴趣来解决它,因为它不会做任何值得调试的事情.你写这个的基本原因.请改用Debug> Step Over.如果你不小心进入了这样一个函数,那么使用Debug> Step Out快速返回你想要调试的代码.

  • 那真好笑.:) (14认同)
  • 调试信息是基于行号的.VS支持的其他语言也可以考虑列号.由于预处理器的原因,它在C和C++中被破坏了,编译器只能在代码被破坏后看到它.哦,这是一个预先处理器.不是那么有趣btw. (9认同)