局部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关键字修饰变量时可以禁止这一优化,每次读都会经过寻址从原地址空间取得变量当时的真实值,所以使用这个关键字时会对性能有一定影响。
volatile保证对特定地址的稳定访问,不会出错。
@iamwzr
夫人您的帐号呢???