C和C++中全局const变量的区别

为研究在目前的C标准和C++标准中全局const变量的区别,做了以下的测试:

(编译器:gcc-4.7.2;环境:32位Ubuntu)

makefile

1
2
3
4
5
6
makec:
g++ -x c test1.cpp test2.cpp -o test
./test
makecpp:
g++ -x c++ test1.cpp test2.cpp -o test
./test

测试0

test1.cpp

1
2
3
4
5
6
7
8
9
const int m;
int x;
#define PRINT(X) printf(#X" = %d\n",X)
int main()
{
PRINT(m);
PRINT(x);
return 0;
}

test2.cpp

1
const int m = 2;

当运行make makec时编译通过,输出为:

m = 0
x = 0

当运行make makecpp时编译不通过,报错:

test1.cpp:1:11: error: uninitialized const ‘m’ [-fpermissive]

结论

C中默认const全局变量与其他的普通全局变量都是默认初始化为0。
C++中默认const全局变量是需要在定义的时候初始化的,否则编译不通过。

测试1

test1.cpp

1
2
3
4
5
6
7
8
9
extern const int m;
int x;
#define PRINT(X) printf(#X" = %d\n",X)
int main()
{
PRINT(m);
PRINT(x);
return 0;
}

test2.cpp

1
const int m = 2;

当运行make makec时编译通过,输出为:

m = 2
x = 0

当运行make makecpp时编译不通过,报错:

test1.cpp:(.text+0xa): undefined reference to `m’

结论

C中默认const全局变量是外部连接的。
C++中默认const全局变量是内部链接的,即具有文件作用域,文件外不可见。

测试2

test1.cpp

1
2
3
4
5
6
7
8
9
extern const int m;
int x;
#define PRINT(X) printf(#X" = %d\n",X)
int main()
{
PRINT(m);
PRINT(x);
return 0;
}

test2.cpp

1
static const int m = 2;

当运行make makec时编译不通过,报错:

test1.cpp:(.text+0xa): undefined reference to `m’

当运行make makecpp时编译不通过,报错:

test1.cpp:(.text+0xa): undefined reference to `m’

结论

C++从C中继承了static说明文件作用域的特性。在这里,static并不决定变量的存储区(全局变量都是存储在全局静态数据区),而是决定了其文件作用域,告知编译器该变量是内部链接的。因为在C++中const默认是内部链接的,所以C++中定义全局const int m = 2就相当于C中定义static const int m = 2

综合结论

在C中用const说明的全局变量与普通的全局变量,除了前者不能主动改变其值外,编译器对其的处理方法都是一样的,都是存储在静态全局数据区,都是默认外部链接,都是默认初始化其内存块为0。

在C++中用const说明的全局变量与普通的全局变量有很大的不同,除了前者不能改变其值外,const说明的全局变量是默认内部链接的,而且没有默认初始化,要求程序员在定义的同时给出初始化的值。这样的特性其实更加严谨,因为内部链接(相当于C中的static)可以防止重名,而常量的定义同时初始化在逻辑上也更合理。