C++ 链接器抱怨 char* 的多个定义,但不抱怨 std::string

Dan*_*nny 4 c++ namespaces constants linker-errors linkage

在一个大项目中,我有一个 .h 文件,它在命名空间中定义了很多常量。引入 const char* 常量会导致链接器错误,抱怨多个定义。

前h

#include <string>
namespace Dv
{
    const int MAX = 10;
    const std::string NAME = "bobo";

    const char* NAME2 = "fred";  // <-- ERROR: multiple definition of `Dv::NAME2'
}
Run Code Online (Sandbox Code Playgroud)

前A.cpp

#include "ex.h"
void aFunction() { printf("this is aFunction\n"); }
Run Code Online (Sandbox Code Playgroud)

前B.cpp

#include "ex.h"    
void aFunction(void);

int main(int argc, char **argv)
{
    aFunction();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译和链接

g++ -c exA.cpp
g++ -c exB.cpp
g++ exA.o exB.o -o ex
exB.o:(.data+0x0): multiple definition of `Dv::NAME2'
exA.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

如果 .h 文件中包含 NAME2,则会发生链接器错误。为什么?

如果 MAX 也是一个 POD(如 char[]?),为什么链接器不会抱怨多个int MAX定义?(或多个std::string NAME定义?)

我不明白 char[] 在这种情况下有什么特别之处。

谢谢

Vla*_*cow 5

根据C++标准(3.5程序和链接)

\n\n
\n

3 具有命名空间范围 (3.3.6) 的名称具有内部链接,如果它是\n

\n\n

\xe2\x80\x94 显式声明为 const 或 constexpr 且既未显式声明为 extern 也未先前声明为具有外部链接的非易失性变量;或者

\n
\n\n

\n\n
\n

4 未命名命名空间或未命名命名空间内直接或间接声明的命名空间具有内部链接。所有其他命名空间都有外部链接。具有名称空间范围且未在上面给出内部链接的名称,如果它是变量的名称,则与封闭名称空间具有相同的链接;或者

\n
\n\n

在这个命名空间定义中

\n\n
namespace Dv\n{\n    const int MAX = 10;\n    const std::string NAME = "bobo";\n\n    const char* NAME2 = "fred";  // <-- ERROR: multiple definition of `Dv::NAME2\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

(唯一的)变量NAME2不是常量,因此具有外部链接。

\n\n

您可以将其设置为具有定义它的内部链接,例如使用关键字 static。例如

\n\n
namespace Dv\n{\n    const int MAX = 10;\n    const std::string NAME = "bobo";\n\n    static const char* NAME2 = "fred";\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者可以将其定义为常量

\n\n
namespace Dv\n{\n    const int MAX = 10;\n    const std::string NAME = "bobo";\n\n    const char * const NAME2 = "fred";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

  • 也许更好的方法是将其设为 const: `const char* const NAME2 = "fred";` ? (2认同)