全局常量和局部常量的区别

局部const

[root@IDC-D-2270 czt]# cat clzd.cpp
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
    const int a = 10;
    int *p = (int *) &a;
    cout << *p << " " << a << endl;
    cout << p << " " << &p << endl;
    *p = 20;
    cout << *p << " " << a << endl;
    cout << p << " " << &p << endl;
    return 0;
}
[root@IDC-D-2270 czt]# g++ clzd.cpp
[root@IDC-D-2270 czt]# ./a.out
10 10
0x7fff93f7736c 0x7fff93f77360
20 10
0x7fff93f7736c 0x7fff93f77360

神奇的事情发生了,const内容被通过指针改动,而且同一空间的内容竟然不同
首先,局部const虽然看上去与全局常量没有什么区别,但编译器在编译时会在栈区为其分配存储空间,所以局部const称作“只读”变量更为恰当。
其次,常量在编译时默认遇到取地址时会为其分配地址
所以这里修改的只是这个副本而本身并未改变
这是编译器优化的结果。被称作常量折叠const folding

全局const

[root@IDC-D-2270 czt]# cat clzd.cpp
#include <iostream>
using namespace std;
const int a = 10;
int main(int argc, char **argv) {
    int *p = (int *) &a;
    cout << *p << " " << a << endl;
    cout << p << " " << &p << endl;
    *p = 20;
    cout << *p << " " << a << endl;
    cout << p << " " << &p << endl;
    return 0;
}
[root@IDC-D-2270 czt]# g++ clzd.cpp
[root@IDC-D-2270 czt]# ./a.out
10 10
0x400b0c 0x7fffd7e4ae78
Segmentation fault

这里会发现,全局const在同样企图通过指针修改其值时会出现段错误,也就是说const全局常量存储空间在常量存储区段上分配,这才是纯粹的只读的常量,所以当企图通过指针修改常量存储区段上的数据时会出现段错误。当然世事无绝对,通过非常手段还是可以修改常量区段的。

而当使用全局const大数组时也会发现:

[root@IDC-D-2270 czt]# cat t.c
int main(){
        const char array[1024000] = {0};
        return 0;
}
[root@IDC-D-2270 czt]# gcc t.c
[root@IDC-D-2270 czt]# ll a.out
-rwxr-xr-x. 1 root root 6423 Feb 11 11:35 a.out
[root@IDC-D-2270 czt]# cat t.c
const char array[1024000] = {0};
int main(){
        return 0;
}
[root@IDC-D-2270 czt]# gcc t.c
[root@IDC-D-2270 czt]# ll a.out
-rwxr-xr-x. 1 root root 1030329 Feb 11 11:18 a.out

编译出的二进制程序中已经为全局常量分配了相应的空间,而局部常量不会,因为常量空间是编译时分配,栈空间是运行时才分配的嘛。
但是如果全局常量数组没有初始化的话编译时也不会分配空间,因为分配一块没有经过初始化的常量空间没有任何意义。

局部volatile const

[root@IDC-D-2270 czt]# cat clzd.cpp
#include <iostream>
using namespace std;
int main(int argc, char **argv) {
    volatile const int a = 10;
    volatile int *p = (int *) &a;
    cout << *p << " " << a << endl;
    cout << p << " " << &p << endl;
    *p = 20;
    cout << *p << " " << a << endl;
    cout << p << " " << &p << endl;
    return 0;
}
[root@IDC-D-2270 czt]# g++ clzd.cpp
[root@IDC-D-2270 czt]# ./a.out
10 10
1 0x7fff4b0a9ac0
20 20
1 0x7fff4b0a9ac0

之前说到常量折叠现象是编译器优化的结果,当使用volatile关键字修饰变量时可以禁止这一优化,每次读都会经过寻址从原地址空间取得变量当时的真实值,所以使用这个关键字时会对性能有一定影响。

发表评论?

3 条评论。

  1. 全局常量和局部常量的区别 | 站点标题 - pingback on 2014/02/11 在 13:26
  2. volatile保证对特定地址的稳定访问,不会出错。

  3. @iamwzr
    夫人您的帐号呢???

发表评论


请输入正确的验证码

Trackbacks and Pingbacks: