ARM Cortex M4 - C 编程和内存访问优化

ARM Cortex M4 - C Programming and Memory Access Optimization

以下三行代码是使用 1 条 MOV 指令修改位的优化方法,而不是使用中断安全性较低的 read-modify-write 习惯用法。它们彼此相同,并在 GPIO 端口的数据寄存器中设置 LED_RED 位:

  1. *((volatile unsigned long*)(0x40025000 + (LED_RED << 2))) = LED_RED;
  2. *(GPIO_PORTF_DATA_BITS_R + LED_RED) = LED_RED;
  3. GPIO_PORTF_DATA_BITS_R[LED_RED] = LED_RED;

LED_RED 就是 (volatile unsigned long) 0x02。在这个微控制器的内存映射中,这个寄存器(和其他寄存器)的前 2 个 LSB 没有被使用,所以第一个例子中的左移是有意义的。

GPIO_PORTF_DATA_BITS_R 的定义是:

#define GPIO_PORTF_DATA_BITS_R ((volatile unsigned long *)0x40025000)

我的问题是:为什么我在使用指针算法或数组索引(分别是第二种方法和第三种方法)时不需要左移两次?我很难理解。提前谢谢你。

记住 C 指针算法的工作原理:向指针添加偏移量以指向的类型为单位进行操作。由于 GPIO_PORTF_DATA_BITS_R 具有类型 unisgned long *,并且 sizeof(unsigned long) == 4,因此 GPIO_PORTF_DATA_BITS_R + LED_RED 有效地添加了 2 * 4 = 8 个字节。

注意(1)对0x40025000进行了运算,它是一个整数,不是指针,所以我们需要加8才能得到相同的结果。左移 2 等于乘以 4,所以 LED_RED << 2 又等于 8。

根据 [] 运算符的定义,

(3) 完全等同于 (2)。