一次看透const

1、什么叫常量

不可以写的叫常量

常量是一个恒定不变的值,它在内存中也是不可修改的。在程序中出现的1、2、3这样的数字或“Hello”这样的字符串,以及数组名称,都属于常量,程序在运行中不可修改这类数据。

——《C++反汇编与逆向分析技术揭秘》

常量被编译进可执行文件中,进程启动后,加载进内存。

2、定义方式

a、#define

b、const

#define修饰的符号名称是一个真量数值,而const修饰的栈常量,是一个“假”常量。在实际中,使用const定义的栈变量,最终还是一个变量,只是在编译期间对语法进行了检查,发现代码有对const修饰的变量存在直接修改行为则报错。

——《C++反汇编与逆向分析技术揭秘》

const 修饰的变量,根据实测,要区分是局部变量还是全局变量。如下图所示全局变量g_val,虽然我们通过指针转换,绕过了编译器检查,但实际在写入操作时,引发异常。

一次看透const_第1张图片

而,如果是局部的const变量,则可以看出,我们对a值修改,已经成功。

一次看透const_第2张图片

查看内存,也可以看到,const 定义的局部、全局变量地址并不相同。根据作用域决定其内存位置和属性。

一次看透const_第3张图片

3、编译器对const修饰的变量做了什么?

编译器检查修饰的变量是否被修改,并且由编译器来限制修改。但是可以被绕过,如之前给的两个图所示。

4、const修饰的内容可以不初始化吗

const修饰的内容可以不初始化吗? —— 不可以。const对象一旦"创建"后其值就不能再改变,所以const对象必须初始化。


先看一个例子:

我们定义未初始化的int变量g_val_0、b,以及指针变量g_ptr_2、p2 —— 编译错误。

但是为什么g_ptr_1(与g_ptr_2 一模一样,只是想说明不要被*与谁挨在一起影响)、p1没初始化就可以?

一次看透const_第4张图片

运行结果:ok

一次看透const_第5张图片


我们先理解创建:就是要分配内存。

const int *p;
const int* p;

a、const 修饰的是 *p

b、p是可以变的,*p是不能变的

c、p 是一个指针,指向的是一个(const int)类型的变量

d、此时,我们只是定义了一个指针p,而不是const对象p。而 const int val;此时就定义/创建了一个const 对象val,类型为int,而创建时没有初始化,因此报错。

一次看透const_第6张图片

可以看到,我们定义了一个指针 p1(没有被const修饰,const修饰的是 *p1),这个指针已经有申请了内存来放置“0x000000919d4ff888”,但是此时这个指向const int类型的指针,并没有初始化,去绑定到一个const int类型的对象。而p2,是一个const 指针,直接被const修饰,因此p2在创建的时候(分配在0x000000919d4ff8a8)必须给个值,也就是&val;

再从汇编的角度来理解:

一次看透const_第7张图片

 我丑丑的画了一下:

一次看透const_第8张图片

可以看到,代码5-6行并没有分配内存,而是在后面8、9行赋值时,才在栈上创建出内存,并初始化。

其实const 的位置只有如下几种,我们来填空并举例:

一次看透const_第9张图片

可以看到,只有一个区分,const是不是挨着变量p。如果挨着变量p,修饰的p就是必须初始化,且p指向的位置不能变化。const 不挨着p的话,修饰的是“*p”,p的指向是可以变的,*p是不能变的。

一次看透const_第10张图片

5、const 和 static 能合起来用吗?

 二者其实是在不同维度来描述属性:

  • const 是只读,创建变量必须初始化

  • static 限制作用域,在内存中的位置不同

从属性上看,二者是不矛盾的,按理也是可以合起来用的。但是对于C++ 函数,要具体分析

你可能感兴趣的:(计算机体系知识,c++,c语言,开发语言)