问题描述
很抱歉,是否曾经有人问过这个问题。我搜索了互联网,但没有找到答案。
假设我有一个文件Common.h
,并且A.cpp
和B.cpp
包含Common.h
。
如果我想在const char *
转换单元中有一个全局Common
,则必须在extern
中使其成为Common.h
,并在Common.cpp
中对其进行定义。否则,如果仅在const char * MSG = "Hello World";
中定义Common.h
,则在编译过程中会出现duplicate symbol
错误。
但是,如果我仅使用Common.h
之类的语句在const int CONSTANT = 10;
中定义一个全局const int,则代码可以编译而不会出现重复的符号错误,并且一切正常。
对于为什么会这样,我感到困惑。在我看来,上面两个示例之间的唯一区别是类型,我认为这没有什么区别。为什么我收到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并拆分定义/声明)之间有什么区别?为什么这两种方法都能解决编译错误,并且两种方法有什么区别?
我还注意到,如果我将const int
变成int
,那么我会再次遇到duplicate symbol
错误。我觉得这背后的原因与上述问题的答案有关。为什么会这样?
解决方法
这是C和C ++的区别之一。
在C ++中,const
变量是隐式static
的变量,即仅对当前翻译单元可见。在C语言中,它隐式extern
对整个程序可见(这也是C和C ++中其他非常量声明的默认值)。
这解释了您的观察。
注意:变量的const char *p
声明不是const
变量。这意味着它指向指向一个常量变量(即*p
不能被修改),但是p
本身不是const
。因此,这里的行为是不同的。 const char * const p
将是const声明。