C++中const和constexpr的多文件链接问题

C++语言支持分离编译,在多文件编程中:变量或函数可以被声明多次,但却只能被定义一次。如果要在多个文件中使用同一个变量,变量的定义能且只能出现在一个文件中,在其他使用该变量的文件中需要声明该变量。如果想声明一个变量而非定义它,就在前面加上关键字extern,并且不能显示初始化变量:

复制代码
//a.cpp
int j = 5;    //定义j并初始化

//b.cpp
extern int j;    //声明j
/*使用j...*/

//以下声明形式是错误的:
//extern int j = 5;

上面的例子中,在b.cpp中,a.cpp里面定义的j是可见的。于是我们对j的使用不会出现错误。

constexpr是C++11标准引入的,constexpr是一种类似于const的常量类型,只能使用常量表达式对constexpr的变量进行初始化,并且编译器在编译时会对表达式是否是常量进行检查,确保用于初始化constexpr变量的表达式的值一定不会在运行时是未知的。对于const和constexpr(C++11)的变量来说,它们默认是内部链接的,也就是说它们只在定义它们的文件中可见。比如:

复制代码
//a.cpp
const int i = 5;
constexpr int j = 10;

//b.cpp
extern const int i;    //错误,i不可见
extern constexpr int j;    //错误,j不可见

在上面的例子中,a.cpp中定义的i和j在b.cpp中是不可见的,b中对于i和j的声明代码会被编译器认为是想要定义常量i和j但却没有初始化,由于const和constexpr在定义时必须初始化,因此编译器会报错。我们可以在定义const变量是加入extern关键字,来指出这个const变量是外部链接的:

复制代码
//a.cpp
extern const int i = 5;
extern constexpr int j = 10;

//b.cpp
extern const int i;    //正确,i是外部链接的
extern constexpr int j;    //错误,不能指定constexpr为外部链接

这里多说一句:变量会在定义时申请存储空间,因此不能使用不完整类型定义变量,而只能使用不完整类型声明变量。