gpt4 book ai didi

c - 为什么 avr-gcc 在扩展我的 [fancy] 宏时告诉我缺少参数?

转载 作者:行者123 更新时间:2023-12-01 13:42:29 26 4
gpt4 key购买 nike

我正在为 Atmel 开发代码,它定义一致的寄存器名称以对端口引脚进行编程。例如:

  • PORTC 传统上用于设置(高或低)端口 C
  • 上的任何引脚
  • PINC 用于读取端口C
  • 上特定引脚的状态
  • DDRC 用于读取/写入端口C 上任意引脚的方向(0=输入,1=输出)

所以我找到了一些code — 我完全理解 — 定义了一个 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 :

#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: error: macro "set_bit" requires 2 arguments, but only 1 given

如果我尝试这个,我也会得到同样的错误:

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

免责声明

代码尚未投入生产。当然,代码可能很丑陋。这主要是一些正在 build 中的基础工作。因此尚未最终确定。

最佳答案

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 时,它会看到已经扩展的序列,包括逗号。

关于c - 为什么 avr-gcc 在扩展我的 [fancy] 宏时告诉我缺少参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38827886/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com