2014-10-29 111 views
1

我正在定義寄存器,用於使用GCC進行編譯的Tiva C系列啓動板。GCC宏1 + 1不等於2?

在頭文件中我有類似的代碼:

樣品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

(是的,我應該更加關注生成的彙編代碼)

+3

我希望這是一個錯字:'#define BASE + PLUS_ONE 0x01',你的意思是'#define PLUS_ONE BASE + 0x01'。 – 2014-10-29 12:22:18

+2

是的 - 你的「宏觀測試」轉載是無稽之談,即使是一個完整的「工作」的例子,它也不會編譯,所以代碼的其餘部分實際上是你運行的是什麼? – 2014-10-29 12:36:14

+0

總是用(和)包含所有的宏參數,否則你只會遇到你提到的那些問題。 – user3629249 2014-10-29 17:46:32

回答

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

現在添加了兩個整數之間發生,結果被轉換爲指針之前,並取消引用。多溫尼爾。

+0

所以強制轉換爲char * – Laurijssen 2014-10-29 12:11:34

+0

我當時認爲預處理器會用一個令牌替換「GPIOB_BASE + 0x420」 - 因此恢復正確的操作順序並執行我的預期操作。感謝您的回答! – 2014-10-29 14:21:26

+0

@DanielDevine預處理器不會做這種算術。它可以評估表達式(例如'#if'),但它不會將結果插入到源代碼中。 – unwind 2014-10-29 14:22:38

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) 

這允許從數據表中取值並忘記指針算術。