我正在定义使用GCC进行编译的Tiva C系列Launchpad的寄存器。
在头文件中,我的代码如下:
示例A
#define GPIOB_BASE 0x40005000
#define GPIOB_AFSEL_R (*((unsigned long *) GPIOB_BASE + 0x420))
#define GPIOB_DEN_R (*((unsigned long *) GPIOB_BASE + 0x51C))
#define GPIOB_PCTL_R (*((unsigned long *) GPIOB_BASE + 0x52C))
为了检查它是否按照我的想法行事,我编写了这个小程序并按预期返回“10”。我继续我的项目,很快遇到了严重的故障(写入不可写的地址)。
宏测试
#include <stdio.h>
#define BASE 0x9
#define BASE + PLUS_ONE 0x01
int main(void){
printf("%d", PLUS_ONE);
}
经过几个小时的拉动我的头发试图调试,我最终用硬编码的等价物替换了地址。
样本B
#define GPIOB_BASE 0x40005000
#define GPIOB_AFSEL_R (*((unsigned long *) 0x40005420))
#define GPIOB_DEN_R (*((unsigned long *) 0x4000551C))
#define GPIOB_PCTL_R (*((unsigned long *) 0x4000552C))
硬故障消失了,事情开始起作用了!
有人可以帮我理解样品A 和样品B 之间的区别吗?
(是的,我应该更加关注生成的汇编代码)
答案 0 :(得分:11)
指针运算不是以字节为单位完成的,它是以指向的对象为单位完成的。
在您的情况下,unsigned long
。所以这个:
((unsigned long *) GPIOB_BASE + 0x420
将导致地址0x40005000 + 0x420 * sizeof (unsigned long)
。假设一个32位long
,那就是0x40006080,这显然不是你想要的。
您应该将宏编写为
#define GPIOB_AFSEL_R (*(unsigned long *) (GPIOB_BASE + 0x420))
现在,在将结果强制转换为指针并取消引用之前,两个整数之间会发生相加。更胜一筹。
答案 1 :(得分:0)
除unwind
的答案外,我建议以不同的方式定义寄存器。
#define GPIOB_BASE 0x40005000
#define GPIOB_REG(offset) (*(unsigned long)(GPIO_BASE + offset))
#define GPIOB_AFSEL_R GPIOB_REG(0x420)
#define GPIOB_DEN_R GPIOB_REG(0x51C)
#define GPIOB_PCTL_R GPIOB_REG(0x52C)
这允许从数据表中获取值并忘记指针算法。