const用法:
const int a
和int const a
:都指定a
为int
类型,并用const
修饰变量a
的值不可变const int *p
:首先p
为指向整数类型的指针变量,const
修饰该指针变量不可变,因此p
所指向的地址的值不可变(p
可以指向别的地址)int* const p
:const
修饰的是p
本身,因此p
的值不可变(不能修改p
指向别的地址)int const *p
:与const int *p
一样,const
修饰指针变量*p
,*p
的值不可变
关于const修饰的变量的位置:
#include <stdio.h>
int a = 1; // 已初始化的全局变量,在.data段
int const b; // 未初始化的全局常量,在.bss段
int const c = 2; // 已初始化的全局常量,可能在.rodata段,具体行为视编译器而定
int main(void)
{
int ab = 3; // 局部变量,在栈
const int d = 4; // 局部常量,在栈
// 以下修改常量的行为编译均不能通过
// b = 1;
// c = 1;
// d = 1;
// 以下行为比较奇妙:
// 由于.bss段是可写的
// 因此采用这种曲线救国的方法对b赋值
// 编译会给出警告,但运行不报错
// 赋值可以成功
int *p1 = &b;
*p1 = 6;
printf("%d\n", b);
// 同理,d所在的栈区是可写的
// 因此编译会给出警告,但运行不报错
// 且赋值能成功
int *p2 = &d;
*p2 = 7;
printf("%d\n", d);
// 以下行为就不一样了
// 如果编译器把全局常量c编译到.rodata段(例如gcc)
// 则编译给出警告,但执行出现段错误(由于企图改写只读段的数据)
// 但如果换用其他实现的编译器,没有把常量写入.rodata段(如tcc)
// 则同p2,给出警告,但赋值成功,运行成功
int *p3 = &c;
*p3 = 8;
printf("%d\n", c);
return 0;
}