为什么我在头文件中定义`const int`时没有出现重复定义错误?
Why is there no duplicate definition error when I define a `const int` in header file?
如果之前有人问过这个问题,我们深表歉意。我在互联网上搜索并没有找到答案。
假设我有一个文件 Common.h
,A.cpp
和 B.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.cpp
、A.h
、B.h
、A.cpp
和 B.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.h
和 Common.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 声明。
如果之前有人问过这个问题,我们深表歉意。我在互联网上搜索并没有找到答案。
假设我有一个文件 Common.h
,A.cpp
和 B.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.cpp
、A.h
、B.h
、A.cpp
和 B.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.h
和 Common.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 声明。