2016-11-14 60 views
30

是否有可能得到一個#defined 整數符號被逐字地插入到字符串文本中,該文字是GCC中的彙編部分的一部分(AVR工作室)?C宏 - 如何獲得一個整數值到字符串文字

我想在下面的asm()塊內的字符串文字中將「LEDS」替換爲48。

#define LEDS 48 //I only want ONE mention of this number in the source 
int x = LEDS; //I'm using the value directly too 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, LEDS  \n\t" //<-- substitution needed here 
... 
} 

但我希望編譯器/彙編(預處理器做了之後它的工作)看到這...

#define LEDS 48 //I only want ONE mention of this number in the source 
int x = LEDS; //I'm using the value directly too 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, 48   \n\t" //<-- substitution needed here 
... 
} 

到目前爲止,我已經嘗試了所有的招數宏我能想到的( #stringification,arg替換,甚至#including具有各種值和雙引號組合的文件以及什麼)。

我完全不熟悉將AVR彙編代碼內聯到AVR Studio的GCC編譯器中的魔力。

我試圖避免在我的源文件中出現多次出現的「48」文字,如果預處理器可以對我進行這種替換,那會很棒。

編輯:這是一個微控制器固件項目 - 只是爲了讓生活變得有趣,幾乎沒有空餘的空間來添加新的代碼。

+0

看看[放置一個預處理指令字符串文字內(http://stackoverflow.com/q/14721007/ 2305521) – fpg1503

+2

爲什麼不進行字符串化和字符串連接? –

+0

@CodyGray,字符串化不會「評估」你傳入的內容,它只是取參數中的字符並將它們直接從vrbatim轉儲出來,除非在字符串化之前使用額外的宏來替換所需的字符。 – Wossname

回答

46

我認爲這是件好事,在你的utils的一個字符串化宏頭部:

#define STR_IMPL_(x) #x  //stringify argument 
#define STR(x) STR_IMPL_(x) //indirection to expand argument macros 

然後你可以保留宏數值並在現場串化:

#define LEDS 48 
int x = LEDS; 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, "STR(LEDS)"  \n\t" 
... 
} 

以上預處理到:

int x = 48; 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, ""48""  \n\t" 
... 
} 

它依賴於一個事實,即相鄰的字符串字面量得到串聯。

+4

這是我的答案的更好的版本。 Upvoted。 – 2501

+0

啊,是的,這似乎是伎倆。我想我有類似的東西,但我的#定義是低音讚賞。燦爛。 – Wossname

13

您需要兩個輔助宏才能工作。然後您可以利用自動字符串連接:

#define STR(x) #x 
#define EXPAND(x) STR(x) 

#define LEDS 48 
int x = LEDS; 

void DrawFrame() 
{ 
    asm(
    "ldi  R27, 0x00  \n\t" 
    "ldi  R26, 0x00  \n\t" 
    "ldi  R18, " EXPAND(LEDS) "  \n\t" 
... 
} 

之所以用兩個宏是僅在第一不會擴大傳入的參數

如果你只是這樣做:

printf("LEDS = " STR(LEDS) "\n"); 

,將擴大到這一點:

printf("LEDS = " "LEDS" "\n"); 

EXPAND宏允許傳入的參數被替換。

所以後來這個:

printf("LEDS = " EXPAND(LEDS) "\n"); 

將擴展到這一點:

printf("LEDS = " "48" "\n"); 
14

可以避開字串宏一塌糊塗,如果你使用的約束:

#define LEDS 48 

void DrawFrame() 
{ 
    asm volatile(
    "ldi R18, %[leds]" 
    : : [leds] "M" (LEDS) : "r18"); 
} 
+1

有趣。此頁面看起來相關:https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html。在這種情況下,我會堅持使用令人討厭的宏,因爲它更容易被C程序員理解(有點!)。 – Wossname

+2

@Wossname:你如何在沒有踩到編譯器的腳趾的情況下使用「basic」asm(沒有約束)(即沒有告訴它的翻轉寄存器)?查看[inline assembly tag wiki](http://stackoverflow.com/tags/inline-assembly/info)瞭解更多信息。 「擴展」asm是使用它的常用方式,AFAIK是唯一安全的方式,而不是使用不影響寄存器的指令(例如內存圍欄或其他)。 –

+0

@PeterCordes,我只使用ASM來獲得在關鍵時間框架內完成的必要指示。一旦ASM返回到C代碼,ASM中使用的所有內存都將重新初始化。彙編輸出表明在這不會是一個問題。但是你提出這一點是正確的,如果我養成了使用AVR組裝的習慣(不太可能),那麼我肯定會研究正確的做法。就目前來看,最糟糕的情況是我的聖誕樹會停止閃爍幾秒鐘。 :) – Wossname

相關問題