C++ VisualStudio2010c++;完全支持类内常量变量?
这个问题与之前提出的一个问题密切相关 <> P>为了使VisualStudio 2010 C++调试器在类初始化的const变量中解析,必须提供变量的全局定义。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 然而,这导致了另一个问题。在非平凡的头文件包含安排(下面给出完整代码)中,
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)