首页 > 编程语言 >C++Const变量的存储位置

C++Const变量的存储位置

时间:2023-07-20 20:44:05浏览次数:36  
标签:存储 const int global C++ diy address Const class

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

相关文章

  • C++架构师 课程目录
    C++架构师课程目录实现指南规划流程在实现"C++架构师课程目录"之前,我们需要先规划整个流程。以下是实现该功能的步骤:步骤描述1.创建课程目录类创建一个C++类来表示课程目录,并定义相关的成员变量和方法。2.添加课程实现向课程目录中添加课程的功能。3.删除课......
  • AnalyticDBMySQL 存储过程
    AnalyticDBMySQL存储过程概述存储过程(StoredProcedure)是一组预编译的SQL语句集合,通过一个名称被调用和执行。在AnalyticDBMySQL中,存储过程可以被用于封装复杂的业务逻辑,提高性能和安全性。本文将介绍AnalyticDBMySQL存储过程的基本概念、使用方法,并提供一些示例代码。存储......
  • 记一次简单的存储过程和Pivot行转列
    首先我很讨厌写存储过程,其次我很讨厌没办法,主要是需要进行行转列,项目经理说可以用Pivot。我不是很精通sql,但是我会百度呀~pivot需要有确定的列名。那我这个项目里面没办法确定,最后问了gpt,使用动态sql(我以前也没用过),不过效果是我想要的,于是乎,改成存储过程吧。简单的存储过程......
  • C++ 模板编程技术解析
    一、函数模板函数模板实现通用函数,根据传递类型进行编译时实参推导:template<typenameT>Tadd(Ta,Tb){returna+b;}intmain(){intx=1,y=2;doublem=1.5,n=2.5;intz=add(x,y);doublep=add(m,n);return0;}这里te......
  • android studio Attribute value must be constant
    解决"androidstudioAttributevaluemustbeconstant"错误的步骤当我们在使用AndroidStudio开发应用程序时,有时会遇到"Attributevaluemustbeconstant"的错误。该错误通常发生在我们尝试在XML布局文件中设置属性的值时。下面是解决该错误的步骤,以及每个步骤需要做......
  • C++/C的#pragma参数选项及其解析
    每种C和C++的实现支持对其宿主机或操作系统唯一的功能。例如,一些程序需要精确控制超出数据所在的储存空间,或着控制特定函数接受参数的方式。#pragma指示使每个编译程序在保留C和C++语言的整体兼容性时提供不同机器和操作系统特定的功能。编译指示被定义为机器或操作系统特定的,并且......
  • linux 存储结构
    存储过程是可以完成特点的一组sql语句完成功能。目录一、存储结构二、实际操作三、存储过程的参数四、总结       一、存储结构1.存储结构概述MysQL数据库存储过程是一组为了完成特定功能的SQL语句的集合。 存储过程这个功能是从5.0版......
  • C/C++ 宏获取当前编译程序工作的CPU指令集平台(综合大全覆盖各类CPU)
    参考:https://blog.csdn.net/liulilittle/article/details/126644547?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-6-126644547-blog-43935465.235%5Ev38%5Epc_relevant_default_base3&dep......
  • Visual Studio新建项目配置好opencv环境,下次打开这个项目后属性管理器显示未加载visua
    配置opencv环境,可参考这篇博客:(82条消息)opencv之visualstudio开发环境配置(属性管理器+环境变量一劳永逸方便开发的配置方式)_opencv官网下载_仙魁XAN的博客-CSDN博客如出现打开这个项目后属性管理器显示未加载visualC++项目,可参考如下方法:1.解决方法:文件→打开→项目/......
  • ARM存储模型
      ARM存储模型数据类型——ARM采用32位架构,基本数据类型有以下三种Byte     8bitsHalfword 16bitsWord    32bits数据存储Word型数据在内存的起始地址必须是4的整数倍......