我正在为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定义了宏以将[我称之为]原始注册表名称转换为实际的内存映射特殊功能寄存器名称(sfr)avr-gcc
:
#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
宏之前,将参数分解为几个。因此,当它看到由后者扩展引起的逗号时,已经为时已晚。
一个常见的技巧是再次扩大论点
#define set_bit0(...) set_bit(__VA_ARGS__)
#define set_output(pin) set_bit0(_PIN(pin))
在这里_PIN(pin)
展开并传递到set_bit0
。从中传递参数时set_bit0
,set_bit
会看到已经扩展的序列,包括逗号。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句