我正在定义使用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))
Run Code Online (Sandbox Code Playgroud)
为了检查它是否正在按照我的想法进行操作,我编写了这个小程序并按预期返回"10".我继续我的项目,并迅速遇到硬故障的大问题(写入不可写的地址).
宏测试
#include <stdio.h>
#define BASE 0x9
#define BASE + PLUS_ONE 0x01
int main(void){
printf("%d", PLUS_ONE);
}
Run Code Online (Sandbox Code Playgroud)
经过几个小时的拉动我的头发试图调试,我最终用硬编码的等价物替换了地址.
样品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))
Run Code Online (Sandbox Code Playgroud)
硬故障消失了,事情开始起作用了!
有人可以帮我理解样品A和样品B之间的区别吗?
(是的,我应该更加关注生成的汇编代码)
unw*_*ind 11
指针算术不是以字节为单位完成的,它是以指向的对象为单位完成的.
在你的情况下,unsigned long.所以这:
((unsigned long *) GPIOB_BASE + 0x420
Run Code Online (Sandbox Code Playgroud)
将导致地址0x40005000 + 0x420*sizeof (unsigned long).假设一个32位long,那就是0x40006080,这显然不是你想要的.
你应该把宏写成
#define GPIOB_AFSEL_R (*(unsigned long *) (GPIOB_BASE + 0x420))
Run Code Online (Sandbox Code Playgroud)
现在,在将结果转换为指针并取消引用之前,在两个整数之间添加.多赢了.