const变量/对象的存储位置
const局部变量
const局部基础变量和自定义变量都存储在栈上
struct diy_class{
int a;
int b;
diy_class(int a, int b ) : a(a), b(b){
}
};
int main()
{
int b = 1; // 这个肯定在栈上
const int a = 10; // 比较a b两个变量的地址,看看a在哪里
printf("address a = %p, address b = %p\n", &a, &b);
const diy_class dd(1,2);
printf("address of diy_class = %p \n", &dd);
// address a = 0x7ffd6926e44c, address b = 0x7ffd6926e448
// address of diy_class = 0x7ffd6926e450
}
对比3个变量的地址, 可知b在栈上。或者你也可以用GDB用 info locals 查看栈上的变量:
(gdb) # 打断点在printf("address a = %p, address b = %p\n", &a, &b);处
(gdb) info locals
b = 1
a = 10
dd = {a = -8016, b = 32767} # 这个栈变量还没有被初始化
const全局变量
再定义一个const全局基础变量,打印其地址
const int global_const_inited = 1; // 存储于只读常量区
int main()
{
int b = 1; // 这个肯定在栈上
const int a = 10; // 比较a b两个变量的地址,看看a在哪里
printf("address a = %p, address b = %p\n", &a, &b);
const diy_class dd(1,2);
printf("address of diy_class = %p \n", &dd);
// address a = 0x7ffd6926e44c, address b = 0x7ffd6926e448
// address of diy_class = 0x7ffd6926e450
printf("address of global_const_inited = %p\n", &global_const_inited);
// address of global_const_inited = 0x560d0df107f8
}
可以看到全局常量的地址明显不在栈上,那在哪? -- 常量数据区,可以用nm命令查看符号表验证:
$ nm const_storage_cpp | c++filt | grep global_const
00000000000007f8 r global_const_inited
其变量名前的符号为r,表示该变量存储在只读常量区。
接下来看看自定义变量:
const int global_const_inited = 1; // 只读常量区
const diy_class global_const_diy(1,2);
int main()
{
int b = 1; // 这个肯定在栈上
const int a = 10; // 比较a b两个变量的地址,看看a在哪里
printf("address a = %p, address b = %p\n", &a, &b);
const diy_class dd(1,2);
printf("address of diy_class = %p \n", &dd);
printf("address of global_const_inited = %p\n", &global_const_inited);
printf("address of global_const_diy = %p\n", &global_const_diy);
// address of global_const_inited = 0x558b9d1dc888
// address of global_const_diy = 0x558b9d3dd018
}
两个地址很相近,那么表示自定义对象的地址也在只读常量区吗? 我们使用nm命令验证以下:
$ nm const_storage_cpp | c++filt | grep global_const
0000000000201018 b global_const_diy
0000000000000888 r global_const_inited
发现并不是,对于只读自定义对象,存储在了BSS段。这与static自定义对象相同,它们都“存储”在了ELF文件的BSS段,并在main函数前完成初始化,详见我之前写的内容。
不能修改const变量?
能修改const变量吗? --- 我们可以绕过编译器的限制,但是不能绕过操作系统的限制。要分情况看:
经过上文的探索,g++对const变量大致分为两种处理方式
- 将变量存储在只读数据段
- 将变量存储在栈和BSS段
操作系统在加载只读数据段时,会将该段设置为只读,无论进程以怎样的方式对它进行修改,都会触发缺页中断的读错误,操作系统在确定进程没有权限进行写时,会立刻向进程强制发送SIGV信号,然后进程就结束了。因此这种类型只读变量的不可变性是由操作系统和ELF格式决定的,无论如何都不能改变这种类型的只读变量。
然而BSS段和栈段是可读、可写的。只要我们通过了编译器的检查,我们可以使用某种方式在运行期对这种类型的只读变量进行修改。
具体可以看看下面的程序:
struct diy_class{
int a;
int b;
diy_class(int a, int b ) : a(a), b(b){
}
};
const int global_const_inited = 1; // 只读常量区
const diy_class global_const_diy(1,2);
int main()
{
// 1. 编译器错误 !
// global_const_diy.a = 10;
// 2. 绕过编译器,成功修改。C++种使用const_cast去除变量的只读属性
diy_class* cc = const_cast<diy_class*>(&global_const_diy) ;
cc->a = 10;
printf("global_const_diy.a = %d\n", global_const_diy.a);
// 3. 逃过编译器的检查,但没能逃过操作系统的检查. Segmentation fault!
int* ee = const_cast<int*>(&global_const_inited);
*ee = 2;
printf("global_const_inited = %d", global_const_inited);
}
注意在C++中,使用const_cast去除变量的只读属性
标签:存储,const,int,global,C++,diy,address,Const,class From: https://www.cnblogs.com/HeyLUMouMou/p/17569629.html