一、C语言中的const变量
- 在c语言中,以const关键字声明的对象,其值不能通过赋值或者递增,递减来修改,所以要一开始初始化变量;
- const修饰的变量不是常量,本质上是 常变量;
const int tmp = 10;//这里不管tmp是全局的,还是局部的
int arry[tmp] = {1, 2, 3};//都会报错,“表达式必须包含常量值”
- const修饰的全局变量,在常量区(.rodata段)分配内存空间,不能通过变量地址来修改值;const修饰的局部变量在栈区分配内存空间,可以通过变量地址来修改值;
- c语言的const修饰全局变量 默认是外部链接的(外部链接:其他源文件 可以使用)。
//c语言的const修饰全局变量 默认是(外部链接的)
//外部链接:其他源文件 可以使用
//fun.c
const int num = 100;//只读的全局变量 内存放在文字常量区(内存空间只读)
//main.c
//对fun.c中的num进行声明(不要赋值)
extern const int num;
void test03()
{
printf("num = %d\n",num);
//num = 200;//err num只读
//C语言中const 修饰变量名 说明变量名为只读(用户不能通过变量名data进行赋值)
const int data = 100;//局部只读变量 内存在栈区(内存可读可写)
//data = 200;//err
printf("data = %d\n",data);
//但是:如果知道data的地址 可以通过地址间接的修改data所对应空间的内容
int *p = (int *)&data;
*p = 2000;
printf("data = %d\n",data);//ok 200
}
二、C++中的const变量
const 在C++中是用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。
1.const全局变量,或者static,extern 关键字
此时该常量是存放在.rodata段的—Read Only Data也就是常量区,是无法通过取地址方式去修改的,修改内容会报段错误(gcc++编译器:Segmentation fault(core dumped)).
例如:
extern const int i=10
static const int i=10
const修饰的全局变量默认是内部链接,即只在当前源文件有效 不能直接用于其他源文件,如果必须用在其他源文件 使用只读的全局变量 必须加extern将变量转换成外部链接。
2.const局部变量内存分配
- c++中 对于基础类型(整数,浮点数,字符) 系统不会给const变量开辟空间 ,会将其放到符号表中;
- c++中当 对const变量取地址的时候 系统就会给它开辟空间;
- 当用变量给const变量赋值时,系统直接为其开辟空间 而不会把它放入符号表中;(下面示例程序中的const变量a)
- const 自定义数据类型(结构体、对象) 和数组系统会分配空间;
fun.cpp
//const修饰的全局变量 默认是内部链接(只在当前源文件有效 不能直接用于其他源文件)
//const int num = 100;
//如果必须用在其他源文件 使用只读的全局变量 必须加extern将num转换成外部链接
extern const int num = 100;
main.cpp
//声明
extern const int num;
struct Person
{
int num;
char name[32];
};
void test04()
{
cout<<"全局num = "<<num<<endl;//err 不识别num
//1、c++中 对于基础类型 系统不会给data开辟空间 data放到符号表中
const int data = 10;
//data = 100;//err 只读
cout<<"data = "<<data<<endl;
//2、c++中当 对data 取地址的时候 系统就会给data开辟空间
int *p = (int *)&data;
*p = 2000;
cout<<"*p = "<<*p<<endl;//空间内容修改成功 2000
cout<<"data = "<<data<<endl;//data 还是10为啥?
//2、当以变量的形式 初始化 const修饰的变量 系统会为其开辟空间
int b = 200;
const int a= b;//系统直接为a开辟空间 而不会把a放入符号表中
p = (int *)&a;
*p = 3000;
cout<<"*p = "<<*p <<endl;//3000
cout<<"a = "<<a <<endl;//3000
//3、const 自定义数据类型(结构体、对象) 系统会分配空间
const Person per = {100,"lucy"};
//per.num = 1000;//err
cout<<"num = "<<per.num<<", name = "<<per.name<<endl;//100 lucy
Person *p1 = (Person *)&per;
p1->num = 2000;
cout<<"num = "<<per.num<<", name = "<<per.name<<endl;//2000 lucy
}
三、关于C++中const变量内存分配的争议
关于c++中const局部变量在程序运行时是否分配了内存有两种观点:
- 一种观点认为 没有为const局部变量分配内存,会将其放到符号表中,
C++高级进阶 第四季:const详解(二) 常量折叠
C++中如何修改const变量
Thinking in C++ 学习笔记(1) 类中的const - 另一种观点 认为分配了,并反汇编代码证明;
C++常量折叠
实践出真知,我们验证下:
实验环境:win10,vs2019(在Linux,g++请自行验证)
-
在release模式下,程序中没有‘&’取地址符:
直接查看tmp变量的地址,显示“无法计算表达式”,说明没有分配内存;
-
在release模式下,程序中有‘&’取地址符:
调试到第六行tmp的地址值为0x007DFC08,该地址中的值为11211500(0x00ab12ec),说明分配了4个字节的内存,里面的值是乱码值,不是10,不是10,不是10。
调试到第九行,tmp的地址值为0x007DFC08,该地址中的值为10;
调式到第11行,tmp的地址值为0x007DFC08,该地址中的值为20;但显示出的tmp:10,说明显示的是符号表中的值,而不是0x007DFC08地址中的。
- Debug模式下,没有‘&’取地址符:
分配了内存
参考文章:细谈c++的const