1. 从单片机开发看常量定义的本质差异
在STM32的GPIO库文件中,我们经常看到这样的引脚定义:
c复制#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
这种写法与const定义有何不同?这要从编译器的处理机制说起。在预处理阶段,所有GPIO_Pin_0都会被直接替换为((uint16_t)0x0001),就像我们用文本编辑器做全局替换一样。这种替换发生在真正的编译开始前,编译器看到的已经是替换后的代码。
而const定义的常量:
c复制const uint16_t GPIO_Pin_0 = 0x0001;
则会在.rodata段分配2字节空间(假设uint16_t为2字节),并将0x0001写入该位置。这个空间有实际的内存地址,可以被取地址操作符&引用。
关键理解:宏定义是"文本替换",const是"只读变量"。前者没有实体,后者有存储空间。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 深入解析两种常量的技术实现
2.1 预处理阶段的宏展开
当编译器遇到:
c复制GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
预处理后会变成:
c复制GPIO_WriteBit(GPIOA, ((uint16_t)0x0001), Bit_SET);
这种替换有三大特点:
- 不占用任何数据段空间(既不在RAM也不在Flash)
- 没有类型检查(只是文本替换)
- 作用域从定义点开始到文件结束(除非被#undef)
2.2 const变量的内存分配
const变量会被分配在只读数据段(.rodata),其内存分配过程如下:
- 编译器在.rodata段预留空间
- 将初始值写入该空间
- 标记该区域为只读属性
- 生成对应的符号表项
对应的汇编代码通常是:
assembly复制ldr r0, =GPIO_Pin_0 ; 从内存加载值
而非宏定义可能生成的:
assembly复制mov r0, #0x0001 ; 直接使用立即数
3. 关键差异对比与技术选型
3.1 内存与性能影响
| 特性 | #define宏常量
