C++ VisualStudio2010c++;完全支持类内常量变量?

C++ VisualStudio2010c++;完全支持类内常量变量?,c++,visual-studio,gcc,scope,initialization,C++,Visual Studio,Gcc,Scope,Initialization,这个问题与之前提出的一个问题密切相关 P>为了使VisualStudio 2010 C++调试器在类初始化的const变量中解析,必须提供变量的全局定义。 e、 g 以下是类定义: class B{ public: static const int m_b=100; }; 以下是成员的全局范围定义: const int B::m_b; 如果没有全局定义,代码可以工作,但调试器无法在b的方法中看到m_b 然而,这导致了另一个问题。在非平凡的头文件包含安排(下面给出完整代码)中,

这个问题与之前提出的一个问题密切相关

<> P>为了使VisualStudio 2010 C++调试器在类初始化的const变量中解析,必须提供变量的全局定义。
e、 g

以下是类定义:

class B{
  public:
   static const int m_b=100;
};
以下是成员的全局范围定义:

const int B::m_b;

如果没有全局定义,代码可以工作,但调试器无法在b的方法中看到m_b

然而,这导致了另一个问题。在非平凡的头文件包含安排(下面给出完整代码)中,Visual Studio生成以下链接错误:

error LNK2005: "public: static int const B::m_b" (?m_b@B@@2HB) already defined in a.obj
1>a.exe : fatal error LNK1169: one or more multiply defined symbols found
但是,GCC成功编译、链接和运行代码

以下是相关代码:

文件a.cpp:

#include <iostream>
#include "a.h"

const int B::m_b;

int main()
{
    B b;
    std::cout << b.m_b;
    return 0;
}
文件b.cpp:

#include "b.h"
文件b.h:

#pragma once

class B {
public:
    static const int m_b = 100;
};
以下是链接器选项(默认VS10控制台程序):

以下是编译器选项(默认VS10控制台程序):


同样,它使用GCC(g++a.cpp b.cpp)成功地构建、链接和运行。我提供的代码是完整的,因此可以复制、粘贴和运行。

根据clang将接受的内容,静态常量变量初始化必须在定义中进行,而不是在声明中进行

因此,在标题中,您需要:

class B{
  public:
   static const int m_b;
};
然后cpp中的定义应该是这样的:

const int B::m_b = 100;

您不应该将数据的非模板定义放在头文件中,因为在链接时会出现多个定义错误。无论变量是成员变量、静态成员变量还是常量静态成员变量,都不会改变这一点

将定义放在一个编译单元中,就像其他任何单例一样


<>这看起来像是一个VisualC++的bug。如果您显示了完整的错误消息,即

b、 对象:错误LNK2005:“公共:静态int常量b::m_b”(?m_b@B@@2HB)已在a.obj中定义 a、 exe:致命错误LNK1169:找到一个或多个乘法定义符号

如果编译器工作正常,则不会在b.obj中的任何位置定义符号


此外,尝试使用
\u declspec(selectany)
告诉我们编译器知道这不是一个定义:

class B{
  public:
   static const int m_b=100;
};
r:\16404173\b.h(3):错误C2496:'b::m_b':'selectany'只能应用于 具有外部链接的数据项


最后,Visual C++清楚地定义了符号(不正确):

R:\16404173>垃圾箱/符号b.obj Microsoft(R)COFF/PE转储程序版本10.00.40219.01 版权所有(C)微软公司。版权所有

此外,我们看到它已经标记为
selectany
。但在实际定义的编译单元中:

class B{
  public:
   static const int m_b=100;
};
(选择任意)
注释消失。这是正确的,这是变量的权威定义

变量出现在
b.obj
中是错误的。编译器通过使用
selectany
注释使简单的case(头文件内的初始化)工作,但是当提供真正的定义时,这种黑客的解决方法就失效了



最后,在a.cpp中的真实定义上添加
\uu declspec(selectany)
,可以解决链接错误。但是我担心这个符号仍然会被链接器优化掉,并且在调试期间不可用。您可以暂时使用
/OPT:NOREF
来避免这种情况(但它会使您的可执行文件膨胀,因此在发货前再次关闭该选项)。

请记住
#pragma once
不是标准。所以VS可能不支持它。导致包含多个头文件。@Named VS确实支持
#pragma once
@Angew Yes它似乎支持。除了@Agnew的评论外,我还尝试了标准的“警卫”,以确保结果是一样的。@MichaelBurr谢谢你,我现在已经更正了。再次阅读代码,看起来你遵循了这个规则。所以应该不会有任何问题。@user2141130:不,您的问题缺少最前面的对象文件名。发生错误的位置与错误的描述一样重要。回答:谢谢。这也是答案。我不确定这里有什么协议,但是如果你想用这个链接来回答这个问题,我会很乐意接受这个答案。<代码> Cuang< <代码>是如何与VisualC++相关的?
const int B::m_b = 100;
Dump of file b.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
000 00AB9D1B ABS    notype       Static       | @comp.id
001 00000000 SECT1  notype       Static       | .drectve
    Section length   2F, #relocs    0, #linenums    0, checksum        0
003 00000000 SECT2  notype       Static       | .debug$S
    Section length   64, #relocs    0, #linenums    0, checksum        0
005 00000000 SECT3  notype       Static       | .rdata
    Section length    4, #relocs    0, #linenums    0, checksum B4446054, selection    2 (pick any)
007 00000000 SECT3  notype       External     | ?m_b@B@@2HB (public: static int const B::m_b)
    Section length    4, #relocs    0, #linenums    0, checksum B4446054
229 00000000 SECTB9 notype       External     | ?m_b@B@@2HB (public: static int const B::m_b)