为什么我在头文件中定义`const int`时没有出现重复定义错误?

Why is there no duplicate definition error when I define a `const int` in header file?

如果之前有人问过这个问题,我们深表歉意。我在互联网上搜索并没有找到答案。

假设我有一个文件 Common.hA.cppB.cpp 包括 Common.h.

如果我想在Common翻译单元中有一个全局的const char *,我必须在Common.h中使它成为extern,并在[=27]中定义它=].否则,如果我简单地在 Common.h 中定义 const char * MSG = "Hello World";,我会在编译期间得到一个 duplicate symbol 错误。

但是,如果我简单地在 Common.h 中定义一个全局 const int 并使用像 const int CONSTANT = 10; 这样的语句,那么代码编译时不会出现重复符号错误,并且一切正常。

我很困惑为什么会这样。在我看来,上面两个示例之间的唯一区别是类型,我认为这不会有什么区别。为什么我得到 C 字符串的重复符号错误,而不是整数?

假设 main.cppA.hB.hA.cppB.cpp 如下所示:

// A.h
#pragma once
void f();
// A.cpp
#include "A.h"
#include "Common.h"

#include <iostream>

void f() {
    std::cout << MSG << std::endl;
}
// B.h
#pragma once
void g();
// B.cpp
#include "B.h"
#include "Common.h"

#include <iostream>

void g() {
    std::cout << CONSTANT << std::endl;
}
// main.cpp
#include "A.h"
#include "B.h"

int main()
{
    f();
    g();
}

现在,假设我们使用命令g++ main.cpp A.cpp B.cpp Common.cpp -std=c++14进行编译。

如果我们使 Common.hCommon.cpp 如下,则编译失败并出现错误 duplicate symbol MSG:

// Common.h
#pragma once
const char * MSG = "Hello World";
const int CONSTANT = 10; // defined in header file
// Common.cpp
// empty

然而,这编译:

// Common.h
#pragma once
extern const char * MSG;
const int CONSTANT = 10; // defined in header file
// Common.cpp
#include "Common.h"
const char * MSG = "Hello World";

我想知道为什么我们需要 extern 来分隔字符串的定义和声明,而不是 int。

有人建议将 C 字符串类型设为 const char * const 而不是 const char *。为什么使指针 const 起作用?另外,在这种情况下,这个解决方案和我上面提供的解决方案(我们将字符串改为 extern 并拆分 definition/declaration)有什么区别?为什么两种方法都解决了编译错误,两种方法有什么区别?

我还注意到,如果我将 const int 变成 int,那么我会再次收到 duplicate symbol 错误。我觉得这背后的原因与我上面问题的答案有关。为什么会这样?

这是C和C++的区别之一。

在 C++ 中,const 变量是隐式的 static,即仅对当前翻译单元可见。在 C 中,它隐式 extern 对整个程序可见(这也是 C 和 C++ 中其他 non-const 声明的默认设置)。

这解释了您的观察结果。

注意:变量的 const char *p 声明不是 const 变量。这意味着它 指向 到一个 const 变量(即 *p 是不可修改的),但 p 本身不是 const。所以这里的行为是不同的。 const char * const p 将是一个 const 声明。