【问题标题】:Does Visual Studio 2010 C++ Fully Support in-Class const Variables?Visual Studio 2010 C++ 是否完全支持类内 const 变量?
【发布时间】:2013-04-30 12:41:30
【问题描述】:

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

为了让 Visual Studio 2010 C++ 调试器解析类内初始化的 const 变量,必须提供该变量的全局定义。


例如

这是类定义:

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;
}

文件 a.h:

#pragma once

#include "b.h"

文件 b.cpp:

#include "b.h"

文件 b.h:

#pragma once

class B {
public:
    static const int m_b = 100;
};

这里是链接器选项(默认 VS10 控制台程序):

/OUT:"a.exe" 
/NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" 
/MANIFEST 
/ManifestFile:"Debug\a.exe.intermediate.manifest" 
/ALLOWISOLATION 
/MANIFESTUAC:"level='asInvoker' uiAccess='false'" 
/DEBUG 
/PDB:"Debug\a.pdb" 
/PGD:"Debug\a.pgd" 
/TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE 

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

/ZI /nologo /W3 /WX- /Od /Oy- /D "_MBCS" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t
/Zc:forScope /Fp"Debug\sndbx.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd
/analyze- /errorReport:queue 

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

【问题讨论】:

  • 记住#pragma once 不是标准的。所以VS可能不支持它。导致包含多个头文件。
  • @Named VS 确实支持#pragma once。
  • @Angew 是的,看来确实如此。 msdn.microsoft.com/en-us/library/4141z1cx.aspx
  • 除了@Agnew 的评论,我还尝试了标准的“守卫”,以确保结果是一样的。
  • @MichaelBurr 谢谢,我现在已经更正了。

标签: c++ visual-studio gcc scope initialization


【解决方案1】:

你不应该把非模板的数据定义放在头文件中,因为你会在链接时得到多个定义错误。变量是成员变量还是静态成员变量还是 const 静态成员变量根本不会改变这一点。

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


这实际上看起来像一个 Visual C++ 错误。如果您显示完整的错误消息,那将有很大帮助,即

b.obj : 错误 LNK2005: "public: static int const B::m_b" (?m_b@B@@2HB) 已在 a.obj 中定义 a.exe : 致命错误 LNK1169: 找到一个或多个多重定义的符号

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


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

r:\16404173\b.h(3) : 错误 C2496: 'B::m_b' : 'selectany' 只能应用于 具有外部链接的数据项


最后,Visual C++ 清楚地定义了符号(错误地):

R:\16404173>dumpbin /symbols b.obj Microsoft (R) COFF/PE Dumper 版本 10.00.40219.01 版权所有 (C) 微软公司。保留所有权利。

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)

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

    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)

(pick any) 注释不见了。说得对,这是变量的权威定义。

变量出现在b.obj 中是完全错误的。编译器通过使用 selectany 注释使简单的情况(在头文件中初始化)工作,但是当提供真正的定义时,这种骇人听闻的解决方法就会失效。


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

【讨论】:

  • 再次阅读代码,您似乎正在遵循此规则。所以应该没有问题。
  • @user2141130:不,您的问题是缺少最前面的目标文件名。发生错误的位置与错误描述同样重要。
  • 已答复,谢谢。这也回答了my previous question。我不确定这里是什么 SO 协议,但如果你想用这里的链接回答这个问题,我很乐意接受这个答案。
【解决方案2】:

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

因此在你的标题中你想要这个:

class B{
  public:
   static const int m_b;
};

然后你的cpp中的定义应该是这样的:

const int B::m_b = 100;

【讨论】:

  • clang 与 Visual C++ 有什么关系?
猜你喜欢
  • 2020-03-19
  • 2018-07-14
  • 1970-01-01
  • 2011-10-05
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多