【问题标题】:Why Doesn't the Visual Studio 2010 Debugger See static const Class Members?为什么 Visual Studio 2010 调试器看不到静态 const 类成员?
【发布时间】:2023-03-08 03:17:02
【问题描述】:

这个问题与随后提出的问题here.密切相关

Stroustrup 描述了定义类内常量的方法here

当我遵循 Stroustrup 的方法时,我看到了预期的结果。但是,在 Visual Studio 2010 中,调试器无法解析该类范围内的 static const 类成员。 这就是我的意思:

#include <iostream>

class Foo {
   public:
    static const int A = 50;
    char arr[A];
    void showA();
};

void Foo::showA() {
    std::cout << "showA = " << A << "\n";
}

int main() {
    Foo f;
    f.showA();
}

当调试器在 showA() 中时,“watch”窗口会报告:

Error: Symbol "Foo::A" not found

我想强调一下,该程序确实按预期运行,即输出是:

showA = 50

程序返回 0。

其他人可以用 Visual Studio 2010 重现这个吗?这是调试器中的错误吗?

【问题讨论】:

  • 请注意,您缺少A 静态数据成员的定义
  • 它是内联的,对 OP 而言
  • 是否启用优化?类是否在命名空间内?
  • @Andy 如果它是内联的,则不是。正如 Stroustrup 文章和 dauphic 的回答所指出的,静态定义是可选的。我刚刚在 VS 中测试了两种方式,并且内联初始化不需要静态 def'n。
  • @AndyProwl 再次感谢 - 所以这里最好

标签: c++ visual-studio gcc compiler-construction debuggervisualizer


【解决方案1】:

Visual C++ 错误地基于类内的声明提供a weak definition (evidence provided in this answer),尽管标准中的语言清晰:

静态数据成员在其类定义中的声明不是定义,并且可能是除 cv-qualified void 之外的不完整类型。静态数据成员的定义应出现在包含该成员的类定义的命名空间范围内。在命名空间范围的定义中,静态数据成员的名称应通过其类名使用:: 运算符进行限定。

根据标准中的另一条规则,如果成员不是odr-used,则不需要定义。

然而,Visual C++ 错误地提供了显式定义还是弱定义并没有区别。如果该成员不是odr-used,则链接器将看不到对它的任何引用并将其删除,从而使调试器对它是否曾经存在感到困惑。使用 Microsoft 链接器,您可以使用 /OPT:NOREF 禁止此优化。

不过,最终这并不是您希望在生产代码中做的事情,因为您的应用程序中会遗留标准库中的各种残留物。但对于调试期间的临时使用,这是一个合理的设置。

【讨论】:

    【解决方案2】:

    您可以在全局命名空间范围内为您的静态数据成员添加一个定义

    const int Foo::A;
    

    添加静态数据成员定义,这不是必需但允许的,似乎可以解决您的问题。

    我在 VS2010 的调试版本中对此进行了测试,当定义存在时,A 的值正确显示在调试窗口中(而当定义丢失时会报告错误消息,与您提到的一致)。

    【讨论】:

    • 感谢您引用标准。对this question 的回答以 111 票赞成指出“类定义 [s] 中的初始化 [ations] 仅允许使用整数和枚举类型”。而且,Stroustrup 的文章似乎暗示只有当您需要访问成员的地址时才需要全局定义。加上代码在 VS10 和 GCC/Cygwin 中“按预期工作”的事实,我敢打赌很多人不会意识到仍然需要全局定义。 +1
    • @user2141130:很高兴这有帮助,实际上仍然需要定义并不明显
    • 它不是 odr 使用的;程序没问题。但是调试器找不到定义。
    • @user2141130:这个答案是在 C++11 更改规则之前发布的——现在可以在类中初始化其他类型。而且 Stroustrup 关于全局定义并不总是需要的说法仍然是正确的。
    • @BenVoigt:好的。我必须承认我还没有设法具体破译 3.2p3,所以我对 odr-used 的理解是有限的。我会相信你并编辑答案,但如果你能解释一下 3.2p3 的哪一部分使A not odr-used(我知道它与“除非”部分,但第一段让我感到困惑)。
    【解决方案3】:

    这不是错误。编译器可以(并且几乎总是会)优化静态常量基本类型。编译器不会为A 分配存储空间,而是将A 的值内联到编译后的指令中。

    因为A 没有存储在任何地方,它没有地址,所以调试器无法查看它。

    【讨论】:

    • 这里 一个错误,虽然不是内联值。编译器实际上会发出一个定义,无论代码是否包含一个(这就是错误),即使每次使用都是内联的。然后 链接器 删除定义,因为没有任何东西取决于它的存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多