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 的区别

项目#defineconst
本质预处理宏替换具有类型的对象声明中的限定符
类型宏名本身无 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,也不等于并发安全。