簡體   English   中英

為什么avr-gcc在擴展我的[奇特]宏時告訴我有關缺少參數的問題?

[英]Why does avr-gcc tell me about missing argument while expanding my [fancy] macro?

我正在為Atmel開發代碼,它為程序端口引腳定義了一致的寄存器名稱。 例如:

  • PORTC傳統上用於設置端口C上的任何引腳(高或低)
  • PINC用於讀取端口C上特定引腳的狀態
  • DDRC用於讀/寫端口C上任何引腳的方向(0 =輸入,1 =輸出)

所以我找到了一些代碼 - 我完全理解 - 定義了一個像這樣的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定義三個宏(例如PINC7PORTC7DDRC7 ),但我主要擔心的是,為了考慮到這種符號,還要重新定義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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM