const常量机制分析

const常量机制分析

const常量机制分析

const为C/C++常用的修饰符,表示该变量是一个常量,不可被修改等含义。那么在实际使用中会存在如下疑问:

1,const修饰的变量是否真的不可修改?

2,如果被修改,会出现什么问题?

3,C和C++中实现机制一样吗?

4,对于内置类型和自定义类型数据,const实现原理一样吗?

5,为什么const变量可以被定义在.h头文件中?

问题1, const修饰的变量是否真的不可修改?

1.1 编译器保证了const修饰的变量不能被修改或者重新赋值。

const int var = 10;

var = 20;//编译报错,不能被修改

1.2 通过指针修改const变量。

const int var = 10;

int* ptr_const = (int*) (&var);

ptr_const = 20;

1) 局部const变量,对于C++程序,该变量地址中的值可以被修改,但是对其的修改不会影响变量实际被引用地方的值。对于c程序,该变量可被修改,且变量使用地方也会受到影响。

对于C++程序:

int main(int argc,char**argv)

{

const int var = 10;

int* ptr_const = (int*) (&var);

printf("ptr_const= %x, var= %x\n", ptr_const, &var);

printf("var= %d, *ptr_const=%d\n", var, *ptr_const);

*ptr_const = 20;

printf("var= %d, *ptr_const=%d\n", var, *ptr_const);

printf("ptr_const= %x, var= %x\n", ptr_const, &var);

可见,对变量地址的值进行修改后,var使用的值也变化,为最新的值。

2)对于全局变量,静态局部变量,全局静态变量都不能被修改,否则会core。

代码:

const int var = 10;

int main(int argc,char**argv)

{

int* ptr_const = (int*) (&var);

printf("ptr_const= %x, var= %x\n", ptr_const, &var);

printf("var= %d, *ptr_const=%d\n", var, *ptr_const);

*ptr_const = 20;

printf("var= %d, *ptr_const=%d\n", var, *ptr_const);

printf("ptr_const= %x, var= %x\n", ptr_const, &var);

return 0 ;

}

运行结果:

可以看到var变量的地址在0x4008c8。

我们来看看0x4008c8是位于程序的的哪个段。

执行命令

readelf -s msgq

看到符号var地址和程序输出的完全一致。其对应的Ndx下标为14,表明该变量存储在msgq文件中的下标为14的段。

执行命令

readelf -S msgq

可见,对变量地址的值进行修改后,var使用的值也变化,为最新的值。

2)对于全局变量,静态局部变量,全局静态变量都不能被修改,否则会core。

代码:

const int var = 10;

int main(int argc,char**argv)

{

int* ptr_const = (int*) (&var);

printf("ptr_const= %x, var= %x\n", ptr_const, &var);

printf("var= %d, *ptr_const=%d\n", var, *ptr_const);

*ptr_const = 20;

printf("var= %d, *ptr_const=%d\n", var, *ptr_const);

printf("ptr_const= %x, var= %x\n", ptr_const, &var);

return 0 ;

}

运行结果:

可以看到var变量的地址在0x4008c8。

我们来看看0x4008c8是位于程序的的哪个段。

执行命令

readelf -s msgq

看到符号var地址和程序输出的完全一致。其对应的Ndx下标为14,表明该变量存储在msgq文件中的下标为14的段。

执行命令

readelf -S msgq

可以看到位于只读数据段.rodata,当然程序不允许修改该地址内的数据,所以会core。

结论:

对于全局变量,局部静态变量,全局静态变量,存储在程序的只读数据段,不能被修改。

2,如果const变量被修改,会出现什么问题?

在问题1中已经得到了结论和验证。

3,C和C++中实现机制一样吗?

3.1不同点:

对于局部const变量,C++在变量具体使用地方通过常量替换实现。C语言中表示只读的变量。

3.2 相同点:

都不能对只读数据段的常量进行修改。如:全局变量,静态局部数据变量,全局静态变量。

4,对于内置类型和自定义类型数据,const实现原理一样吗?

4.1局部变量

内置类型和自定义类型完全一样,都没有分配存储空间。运行时在栈空间存储,每次运行地址不定,可以通过指针修改其值。

代码

struct test

{

int var;

test(int x)

{

var = 30*40;

}

};

int main(int argc,char**argv)

{

const test testObj(5);

int* ptr_Obj = (int*) (&testObj.var);

printf("ptr_const= %x, var= %x\n", ptr_Obj, &testObj.var);

printf("ptr_const= %d, var= %d\n", *ptr_Obj, testObj.var);

*ptr_Obj = 40;

printf("ptr_const= %d, var= %d\n", *ptr_Obj, testObj.var);

}

运行结果:

4.2全局变量或者静态变量(全局和局部)

自定义类型const变量存分配空间,存储在bss段,且可以被修改。

内置类型const变量分配空间,存储在只读数据段.rodata,不能被修改。

代码

struct test

{

int var;

test(int x)

{

var = 30*40;

}

};

static const test testObj(3);

int main(int argc,char**argv)

{

int* ptr_Obj = (int*) (&testObj.var);

printf("ptr_const= %x, var= %x\n", ptr_Obj, &testObj.var);

printf("ptr_const= %d, var= %d\n", *ptr_Obj, testObj.var);

*ptr_Obj = 40;

printf("ptr_const= %d, var= %d\n", *ptr_Obj, testObj.var);

}

结果:

查看符号表

readelf -s msgq

查看段表

可以看到位于.bss段。

5,为什么const变量可以被定义在.h头文件中?

我们都知道,.h头文件中不能有定义。其中const变量,类和模版是特例。

5.1 在.h中声明const变量

在头文件中extern const int var;//声明

在cpp文件中只能定义一次,否则会出现重定义。

因为这种情况生成的.o文件符号表存在var。

5.2在.h中定义const变量

在头文件中定义const变量

const int var =10;

在多个cpp文件中引用该文件。并把cpp对应生成的.o文件链接为可执行程序。

可以正常编译链接,不会报错。

会对该const变量分配空间,且被重复存储在不同只读数据段。重复次数和引用该.h文件的cpp生成的.o文件个数一致。且各存储地址不一样,都不能通过指针被修改。

查看符号表。

可以看到存在两个var符号,地址不同。

运行结果

各cpp文件读取对应的只读数据段的数据,互不影响。

特别注意点:

对于头文件定义字符串指针常量的正确定义如下:

const char * const constCharPtr="hello const";

表示指针常量,则可以放在头文件。

而不是常量指针,下面这句在头文件中,如果被多个cpp包含。则会出现重定义。

const char *constCharPtr="hello const";

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏青玉伏案

窥探Swift编程之错误处理与异常抛出

在Swift 2.0版本中,Swift语言对其错误处理进行了新的设计,当然了,重新设计后的结果使得该错误处理系统用起来更爽。今天博客的主题就是系统的搞一下Swi...

21650
来自专栏软件测试经验与教训

上期答案

34250
来自专栏C语言及其他语言

【优秀题解】绝对值排序】(合并排序详解+图解)

原题链接:http://www.dotcpp.com/oj/problem1169.html (大家可以自行提交) 解题思路: 1.采用分治法思想,把整个序列...

57380
来自专栏微信公众号:Java团长

Java面试题整理及参考答案

允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用).主要有以下优点:

13720
来自专栏noteless

[二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

JVM全称是Java Virtual Machine  ,既然是虚拟机,他终归要运行在物理机上

30010
来自专栏JAVA高级架构

为什么要用单例模式?

10420
来自专栏专注 Java 基础分享

字节码文件的内部结构之谜

如果计算机的 CPU 只有「x86」这一种,或者操作系统只有 Windows 这一类,那么或许 Java 就不会诞生。Java 诞生之初就曾宣扬过它的初衷,「一...

41090
来自专栏desperate633

深入理解Java Runtime Area Java运行时数据区Java Runtime Area的分类从线程的角度理解Java Runtime Area从存储内容理解Java Runtime Are

具体的每个区域的内容和特点可以参考《深入理解Java虚拟机》,此书已经讲的很详细了。 下面我们对这几个数据区域进行分类,分别从不同的视角来分析,加深我们的理解

8910
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列8

? 一、heap和stack有什么区别 栈是一种线形集合,其添加和删除元素的操作应在同一段完成。 栈按照后进先出的方式进行处理。 堆是栈的一个组成元素 ...

32150
来自专栏jessetalks

Javascript基础回顾 之(二) 作用域

参数传递的问题   在Javascript中所有的参数传递都是按值传递的。也就是说把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。...

28960

扫码关注云+社区

领取腾讯云代金券