“c 语言中 const 修饰的变量是一个常量,常量在程序运行时不能修改,只能在变量声明的时候初始化。”
但是
也要看变量是全局变量还是局部变量,全局变量不能修改,局部变量可以修改。
用下边的代码来做实验。
const 变量直接赋值,不管是全局变量还是局部变量,编译的时候会报错,编译不通过。
但是如果把变量的地址取出来,然后通过地址操作来间接修改 const 变量,这个时候可以编译通过。执行的时候,不同的变量是有区别的:写全局常量和局部静态常量会出现段错误,程序崩溃;写局部常量,可以操作成功。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const int global_const_a = 100;
int main() {
const int local_const_b = 200;
const static int local_const_static_c = 300;
printf("a: %d, b: %d, c: %d\n", global_const_a, local_const_b, local_const_static_c);
// local_const_static_c = 101; // (1)编译错误
// local_const_b = 201; // (2)编译错误
// local_const_static_c = 301; // (3)编译错误
int *pa = &global_const_a;
int *pb = &local_const_b;
int *pc = &local_const_static_c;
// *pa = 102; // (4)运行时段错误
*pb = 202; // (5)运行没有问题
// *pc = 302; // (6)运行时段错误
printf("a: %d, b: %d, c: %d\n", global_const_a, local_const_b, local_const_static_c);
return 0;
}
原因:
全局常量和局部静态常量保存在只读数据段,只读数据段没有写权限,所以运行的时候写会报段错误;局部常量保存在栈里,栈是可读可写的,所以运行的时候写没有问题。
为了便于分析,我们把上边代码的 printf 都注释掉,然后通过如下命令编译出目标文件:
gcc -c xxx.c -o xxx.o
然后使用 objdump -h -s const.o 来查看目标文件的段信息。从如下截图中可以看出,目标文件主要包括代码段 .text,数据段 .data, .bss 段,只读数据段 .rodata。其中只读数据段的长度是 8,正好和上边的代码相匹配,两个 int 类型,长度是 8。
代码段 .text | 保存代码指令 |
数据段 .data | 保存已经初始化的全局变量和局部静态变量 |
.bss 段 | 保存未初始化的全局变量和局部静态变量 |
只读数据段 .rodata | 保存只读数据 |