为什么C++中允许常量全局变量的多重定义,而C中不允许

Why is multiple definition of a const global variable allowed in C++ and not in C?

本文关键字:定义 不允许 许常量 C++ 为什么 常量 全局变量      更新时间:2023-10-16

由于一个定义规则,在C或C++中不允许对全局变量进行多个定义。然而,在C++中,const全局变量可以在多个编译单元中定义,而不会出错。这与C.不同

为什么C++允许这样做,而C不允许?为什么与C相比,C++中常量全局变量的用法和行为与非常量全局变量有这种不同?C++和C在const的覆盖下发生了什么?

例如,这在C++中是允许的,但在C:中是错误的

// Foo.cpp
const int Foo = 99;
// Main.cpp
const int Foo = 99;
int main()
{
    cout << Foo << endl;
    return 0;
}

这对C来说是好的,但对C++来说是错误的:

// Foo.cpp
const int Foo = 99;
// Main.cpp
extern const int Foo;
int main()
{
    cout << Foo << endl;
    return 0;
}
// Foo.cpp
const int Foo = 99;
// Main.cpp
const int Foo = 99;

命名空间作用域上的const变量具有内部链接。所以它们基本上是两个不同的变量。没有重新定义。

来自@David的评论,3.5/3[基本链接]:

具有命名空间范围的名称(3.3.5)具有内部链接(如果是名称)的--对象、引用、函数或显式的函数模板声明为静态或,
--物体或显式声明的引用const和均未显式声明extern或之前声明为具有外部链接;或
--数据成员一个匿名工会。


在第二种情况下,您应该这样做(正确的方式):

//Foo.h
extern const int Foo; //use extern here to make it have external linkage!
// Foo.cpp
#include "Foo.h"
const int Foo = 99; //actual definition goes here
// Main.cpp
#include "Foo.h"
int main()
{
   cout << Foo << endl;
}

我认为您询问的是基本原理,而不是允许这样做的特定语言规则。

这样做的理由是它使const变量更易于使用。它给出了#define的一个常用用法的类型替换。

您可以完全相同的方式使用const int max_count = 211;,而不是#define MAX_COUNT 211,例如共享头文件,而不必担心将一个定义放在哪里。

您不能合法更改const对象的值,因此一个对象和多个具有相同值的对象之间没有明显区别。

由于您可以将const对象的定义放在头文件中,因此编译器在编译阶段直接使用该值是很简单的,而不必将此类优化延迟到链接时间修复。

基本上,在C++中,const、非局部变量是真正的常量表达式或constexpr。这允许做很多事情,比如TMP。

const int five = 5;
int main() {
    int x[five];
    std::array<int, five> arr;
}

在C中,它们只是一个不能修改的变量。也就是说,

const int five = 5;
int main() {
    int x[five]; // Technically, this is a variable length array
}

相当于

int five = 5;
int main() {
    int x[five];
}

实际上,C++将某些类型的const变量提升为一个新的类别constexpr,而在C中,这并不存在,它们只是碰巧不可修改的变量。

看起来const实际上并没有生成外部符号。

为什么英国人拼写COLOUR,而美国人拼写COLOR

它们是来自同一基础的两种不同语言,但它们没有相同的规则。

C&C++是一样的。如果它们没有不同,它们就会被称为相同的东西。

我的解决方法是将其声明为:

static classfoo foo;

它在我的情况下起了作用。