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

问题描述

很抱歉,是否曾经有人问过这个问题。我搜索了互联网,但没有找到答案。

假设我有一个文件Common.h,并且A.cppB.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.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并拆分定义/声明)之间有什么区别?为什么这两种方法都能解决编译错误,并且两种方法有什么区别?

我还注意到,如果我将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声明。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...