C++深度解析 进化后的const分析(2)
1 C语言中的const变量
C语言中的const变量是只读变量,其本质还是变量,会分配存储空间。(通过枚举enum定义真正的常量)
由于const局部变量会存放在栈里,而const全局变量会存在只读存储内存上。
所以我们可以通过指针来修改const局部变量,但是修改const全局变量,会使程序崩溃
示例1:
通过指针来修改const局部变量
#include <stdio.h>
int main()
{
const int c = 0; //const局部变量
int* p = (int *)&c; //通过指针修改const变量
*p = 5;
printf("c = %d\n", c);
return 0;
}
输出结果:
示例2:
#include <stdio.h>
const int c = 0; //const全局变量
int main()
{
int* p = (int *)&c; //通过指针修改const变量
*p = 5;
printf("c = %d\n", c);
return 0;
}
输出结果:
由于指针修改只读存储区的数据,所以导致程序崩溃。
2 C++中的const常量
在C++中,const变量则是真正的常量了,定义时会将其放入符号表中。
所以编译途中遇到使用const变量时,则直接从符号表中取出常量
只要当该const变量为全局(使用extern声明过),或者被使用&操作符时,才会被分配存储空间。
示例代码:
#include <stdio.h>
int main()
{
const int c = 0; //const局部变量
int* p = (int *)&c; //使用&操作符,会分配空间
*p = 5;
printf("c = %d, p=%d\n", c, *p);
return 0;
}
结果如下:
为什么输出结果会有两个不同的值?
这是因为使用&c时,会从符号表中取出c的值,并将0存在一个新的分配空间地址里,所以*p修改的只是分配出来的空间地址内容,而c还是常量。
3 符号表
就是编译器在编译过程过程中产生的一张表。(符号表是编译器的内部结构)
所以为c分配的4字节的空间,毫无意义。只是为了兼容c语言。
//将常量c(标识符)存入符号表
const int c = 0;
//为标识符c分配4个字节空间,并不使用
int* p = (int *)&c;
printf("Begin...\n");
//修改的是编译器为标识符c分配的空间
*p = 5;
//编译器会查看符号表,发现里面c,值是c
printf("c = %d\n", c);
printf("End...\n");
4 C++的const 和 宏定义
4.1 C++中的的const常量类似于宏定义
const int c = 5; ≈ define c 5
4.2 C++中的const常量在与宏定义不同
const常量是由编译器处理,编译器对const常量进行类型检查和作用域检查。
define宏定义由预处理器处理,单纯的文本替换,不会进行各种检查
(预处理器是执行编译器之前运行的程序,用来删减注释,宏变量转换等)
示例代码:
#include <stdio.h>
void f()
{
//宏是被预处理器处理的,直接进行文本替换
#define a 3 //定义宏
const int b = 4;//定义局部变量
}
void g()
{
printf("a = %d\n", a); //a=3
//printf("b = %d\n", b); //b的作用域f(),在f之外是不能访问b
}
int main()
{
const int A = 1;
const int B = 2;
//从符号表中取出数值
int array [A + B] = {0};
int i = 0;
for(i = 0; i < (A+B); i++)
{
printf("array[%d] = %d\n", i, array[i]);
}
f();
g();
return 0;
}
因为执行预处理器时,会将预见到的所有a变为3,所以编译器看到的是printf("a = %d", 3);
而取消//printf("b = %d\n", b);屏蔽后,程序则会报错,是因为b的作用域只在f()函数里有效
5 小结:
C++中的const是一个真正意义上的常量
C++编译器可能会为constchan常量分配空间
C++完全兼容Cyu'y语言中const常量的语法特性