GCC宏1 + 1不等于2?

时间:2014-10-29 12:06:05

标签: c gcc macros

我正在定义使用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 之间的区别吗?

(是的,我应该更加关注生成的汇编代码)

2 个答案:

答案 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)

这允许从数据表中获取值并忘记指针算法。