在 STM32 上使用 register 关键字
在 STM32 上使用 register
关键字时,有一些特别需要注意的事项。虽然 register
是 C 语言中的一个标准关键字,它用于提示编译器将变量尽可能存放在寄存器中,以加速访问,但在 STM32 这样的嵌入式平台上,还是需要考虑几个方面:
1. STM32 的寄存器有限
STM32 的微控制器(MCU)拥有有限数量的寄存器(通常是 16 个通用寄存器)。因此,register
并不会将所有变量都放入寄存器,而是依赖于编译器的智能选择。
注意点:
- 如果声明的局部变量比较多,编译器可能会选择不将所有变量都放入寄存器。
- 在 STM32 系列中,尤其是小型型号(如 STM32F030,STM32F1 系列),寄存器资源非常紧张,过度使用
register
可能会导致寄存器分配冲突或性能下降。 - 对于大多数情况下,编译器会自动优化局部变量,通常不需要显式使用
register
。
2. register
变量不能取地址
使用 register
声明的变量不能使用 &
操作符取其地址,因为它们是寄存器变量,不能被直接访问。如果你尝试取寄存器变量的地址,编译器会报错。
register int x = 10;
int *p = &x; // 编译错误:无法取寄存器变量的地址
如果在代码中需要取变量的地址,那么应该避免使用 register
。
3. register
和优化设置
对于嵌入式开发,STM32 的编译器(如 Keil5)通常会做自动优化。尤其是在开启 -O3
或 -Os
优化选项时,编译器会自动根据情况将局部变量存放到寄存器中,实际上很多时候你并不需要手动指定 register
。
-O3
优化: 该优化等级下,编译器会最大程度优化代码,包括变量寄存器分配,因此许多情况下,即使不使用register
,编译器也会将频繁使用的变量存储在寄存器中。-Os
优化: 该选项关注代码的尺寸,编译器会尽可能减少代码大小,同时考虑将变量放入寄存器中,以提升性能。
在启用这些优化时,register
关键字的作用可能会显得不那么重要,因为编译器已经在做类似的优化。
4. 特殊寄存器
对于 STM32 微控制器,除了普通的通用寄存器外,还有一些专用寄存器(如 SFR, 特殊功能寄存器)。这些寄存器和通用寄存器有所不同,它们用于控制外设、系统设置等。使用 register
时,不能期望 STM32 编译器会将这些特殊寄存器存入普通的通用寄存器。
建议:
- 如果操作的是硬件寄存器(如
GPIO
,USART
等外设寄存器),应该直接使用该外设的寄存器地址,而不应依赖register
关键字。
5. register
和 STM32 外设访问优化
在 STM32 中访问外设寄存器时,寄存器的值往往是需要直接映射到内存的。在这种情况下,编译器可能会将外设寄存器地址作为指针处理,而不是使用 register
来优化。对于外设的寄存器,手动优化(例如通过 DMA 或通过内存映射外设等)通常比使用 register
更为有效。
6. register
和 ARM 架构
STM32 微控制器基于 ARM Cortex-M 内核(如 Cortex-M3、M4、M7)。ARM 处理器本身有一套高效的寄存器管理和流水线机制,编译器在优化时会根据 ARM 的特点做相应优化。
注意:
- ARM 处理器已经具有相对较多的寄存器(如 ARM Cortex-M4 有16个通用寄存器),如果使用
register
,编译器会尽量选择合适的寄存器来存放变量。 - 对于复杂的 ARM 指令集,编译器会在优化时选择合适的寄存器使用策略,因此即使不显式声明
register
,编译器通常也能合理地优化寄存器的使用。
总结:
在 STM32 上使用 register
时,有以下几点需要特别注意:
- 有限的寄存器资源:STM32 的寄存器数量有限,过度使用
register
可能会导致寄存器分配冲突。 - 不能取地址:声明为
register
的变量不能取地址,因此如果需要传递指针或取地址,不能使用register
。 - 编译器优化:Keil5 等编译器会自动进行优化,通常在开启高级优化(如
-O3
)时,不需要显式使用register
,编译器会自动决定将局部变量放入寄存器中。 - 适用场景:
register
最适用于频繁访问的局部变量,但对于 STM32 外设寄存器操作,应直接操作地址,而不应使用register
。
在 STM32 的开发过程中,很多时候依赖编译器的优化能力,特别是在 Keil5 环境下,编译器的优化已经非常强大,因此对 register
的使用可以保持谨慎,并根据实际情况决定。