[英]Why does avr-gcc tell me about missing argument while expanding my [fancy] macro?
我正在為Atmel開發代碼,它為程序端口引腳定義了一致的寄存器名稱。 例如:
所以我找到了一些代碼 - 我完全理解 - 定義了一個像這樣的PIN宏:
#define LED_PIN C,7
然后是以下宏(僅限於我在這里討論的用例):
#define _BV(bit) (1 << bit)
...
#define _SET(type, name, bit) type ## name |= _BV(bit)
#define _CLEAR(type, name, bit) type ## name &= ~ _BV(bit)
#define _TEST(type, name, bit) ( type ## name & _BV(bit) )
...
#define OUTPUT(pin) _SET(DDR, pin)
#define INPUT(pin) _CLEAR(DDR, pin)
...
#define HIGH(pin) _SET(PORT, pin)
#define LOW(pin) _CLEAR(PORT, pin)
所以我可以編寫一個函數main()
,如下所示:
main() {
OUTPUT(LED_PIN);
HIGH(LED_PIN);
}
雖然非常方便並且不能僅為一個LED定義三個宏(例如PINC7 , PORTC7和DDRC7 ),但我主要擔心的是,為了考慮到這種符號,還要重新定義AVR宏,同時考慮到AVR宏使用SFR寄存器作為參數(來自sfr_defs.h ):
#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
此外,AVR定義了從[我稱之為]裸注冊表名稱轉換為avr-gcc
實際內存映射特殊功能寄存器名稱(sfr)的宏:
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
和_SFR_ADDR()
根據目標Atmel CPU添加偏移量0或20。 因此,為了增強與那些采用SFR寄存器和可選參數的AVR庫函數的兼容性,我決定重寫初始代碼並嘗試以下方法:
#define _SFR_BIT(type, name, bit) type ## name, bit
#define _PORT(pin) _SFR_BIT(PORT, pin)
#define _PIN(pin) _SFR_BIT(PIN, pin)
#define _DDR(pin) _SFR_BIT(DDR, pin)
#define set_bit(sfr, bit) _SFR_BYTE(sfr) |= _BV(bit)
#define set_output(pin) set_bit(_PIN(pin))
但是當我在函數main()
寫這樣的東西時,我會遇到編譯器錯誤消息:
set_output(LED_PIN);
main.cpp:72:19:錯誤:宏“set_bit”需要2個參數,但只有1個給定
如果我嘗試這個,我也會得到同樣的錯誤:
#define set_output(pin) set_bit(_SFR_BIT(DDR, pin))
為什么宏OUTPUT()
只傳遞三個參數中的兩個到_SET()
編譯好,而我的宏沒有?
正如Jens Gustedt所指出的,通用解釋在於編譯器解析宏的順序。
要使用宏將任意數量的參數轉換為具有固定數量參數的函數,可以將函數名稱作為宏的參數:
#define EXPAND(f, ...) f(__VA_ARGS__)
#define _SFR_BIT(type, name, bit) type ## name, bit
...
#define set_bit(sfr, bit) _SFR_BYTE(sfr) |= _BV(bit)
...
#define set_output(pin) EXPAND(set_bit, _SFR_BIT(PIN, pin))
在沒有任何“ 參數缺失 ”編譯器錯誤的情況下解析傳遞給函數(第一個參數)的參數和參數 。
精致版本:
#define _SFR_X(f, type, name, bit) f(type ## name, bit)
...
#define set_bit(sfr, bit) _SFR_BYTE(sfr) |= _BV(bit)
...
#define set_output(pin) _SFR_X(set_bit, PIN, pin)
免責聲明
該代碼尚未生產。 當然,代碼可能很難看。 這主要是一些正在建設的基礎工作。 因此尚未最終確定。
的論點分解set_bit
成幾個發生在之前_SFR_BIT
宏expandend。 因此,當它看到后者擴展所產生的逗號時,已經為時已晚。
一個常見的技巧是再次擴大論點
#define set_bit0(...) set_bit(__VA_ARGS__)
#define set_output(pin) set_bit0(_PIN(pin))
這里_PIN(pin)
展開並傳遞給set_bit0
。 將參數從set_bit0
傳遞給set_bit
它會看到已經擴展的序列,包括逗號。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.