04 const 与指针、宏常量
1. const 的作用
const 是类型限定符,限制通过对应类型的左值修改对象,不等于对象一定存放在只读内存,也不代表原本可修改的对象不会通过其他途径改变。
int a = 10;
const int *p = &a;
a = 20; // 合法:a 本身不是 const 对象
// *p = 30; // 不合法:不能通过 p 修改
如果对象本身定义为 const,强制去掉限定再修改它属于未定义行为。
2. const 与指针
| 声明 | 能通过 p 修改 *p | 能改变 p 的指向 |
|---|---|---|
int *p | 能 | 能 |
const int *p | 不能 | 能 |
int * const p | 能 | 不能 |
const int * const p | 不能 | 不能 |
理解方法:看 const 限定的是指向的数据还是指针本身。int const *p 与 const int *p 等价。
3. 指针参数与 const
void read_data(const uint8_t *p); // 只通过 p 读取
void write_data(uint8_t *p); // 可以通过 p 写入
uint8_t *可以隐式转换为const uint8_t *。const uint8_t *不能直接隐式转换为uint8_t *,否则会丢失限定符,编译器需要诊断。const常用于声明函数不会通过该指针修改数据的接口意图,但不自动保证线程安全。
4. const 与 #define 的区别
| 项目 | #define | const |
|---|---|---|
| 本质 | 预处理宏替换 | 具有类型的对象声明中的限定符 |
| 类型 | 宏名本身无 C 类型 | 对象有明确类型 |
| 作用范围 | 遵循预处理宏规则 | 遵循 C 作用域规则 |
| 常量表达式 | 展开后可能形成整数常量表达式 | C11 中普通 const int 不是整数常量表达式 |
#define BUF_SIZE 16
const int max_size = 16;
int buffer[BUF_SIZE]; // 文件作用域下合法
// int other[max_size]; // 标准 C11 文件作用域下不合法
函数式宏要注意括号,避免运算优先级错误:
#define DOUBLE(x) ((x) + (x))
宏参数可能被求值多次,不要随意传入 i++ 等有副作用的表达式。
5. 嵌入式中的存储位置与 volatile
const不保证对象位于 Flash;存放位置由编译器、链接脚本及硬件决定。- 静态存储期的只读数据常被放入
.rodata并映射至 Flash,但不是语言层面的保证。 const volatile可以用于硬件自主更新、软件只读访问的寄存器:const限制通过该接口写入,volatile约束编译器的访问优化。
6. 复习要点
const int *p:指向的内容不可通过p修改。int * const p:指针p本身不能改指向。- 给指针目标类型增加
const通常允许;隐式去掉不允许。 #define是预处理替换;const是类型限定。const不等于 Flash,也不等于并发安全。