关于C/C++的单定义规则
在这里通过简单的程序对C和C++的单定义规则进行测试和说明以加深理解。
我们知道一般头文件包含的内容有:
- 函数原型
- 使用
#define
或const
(仅对于C++而言)定义的符号常量 - 结构声明
- 类声明
- 模板声明
- 内联函数
正常在头文件中的内容是不进行内存分配的,例如若是变量则同一个变量会被重复定义声明,同理函数定义也是。所以也不能使用#include
来包含源代码文件,也会导致多重声明。
单定义规则(One Definition Rule, ODR)
单定义规则(One Definition Rule, ODR):变量只能有一次定义。
什么是定义?
C++提供了两种变量声明:
- 定义声明(defining declaration)或简称定义(definition):给变量分配存储空间。
- 引用声明(referencing declaration)或简称为声明(declaration):它不给变量分配存储空间,因为它引用已有的变量。
下面来简单测试下C语言和C++的单定义规则
共三个文件:
- test.h
1
2
3// 定义两个常规变量
int var1 = 1;
double var2 = 2; - file1.c
1
2
3
4
5
6
7
8
9
int main(void)
{
printf("%d", var1);
printf("%f", var2);
return 0;
} - file2.c
1
2
3
4
5
6
7
8
9
int main(void)
{
printf("%d", var1);
printf("%f", var2);
return 0;
}
按照翻译单元(文件)单独编译每个文件时编译并不会出问题。但将目标文件链接时便有multiple definition的报错
(使用g++也会出现同样的错误)
因此C语言和C++都会受到单定义规则的约束。
const限定符
先上例子吧,在test.h中的变量前全部添加const
限定符,分别使用gcc和g++对相应的C和C++翻译单元进行编译。
test.h1
2const int var1 = 1;
const double var2 = 2;
若用gcc进行编译链接后仍会报错multiple definition
但是用g++编译则没有报错
这里就可以看出:
和C语言不同,C++中,const限定符对默认的存储类型稍有影响。在默认情况下全局变量的链接性为外部的,但是用了const限定符使得全局变量的链接性为内部。也就是说在C++看来,全局const定义就像使用了static说明符一样。
1 | const int fingers = 10; |
相当于
1 | static int fingers = 10; |
这样把
const
常量放在头文件中,然后每个文件包含头文件也只是相当于增加了文件内部链接的常量,链接成一个程序并不会出现违背单定义规则的双重定义的情况出现。
如果处于某种原因,希望某个常量的链接性为外部的,则可以使用extern关键字来覆盖默认的内部链接性。
1 | extern const int states = 50; |
总结
- C和C++中变量定义都有单定义规则的约束。
- C++中
const
限定符和static
功能类似,C语言中则不是。