【问题标题】:Overloading a macro with two arguments用两个参数重载宏
【发布时间】:2014-10-30 20:49:46
【问题描述】:

我有一堆 #defines,它们看起来都像这样 #define D, 0,它们包含一个来自 AD 的字母和一个 0-8 的数字,用逗号分隔。

现在我正在尝试创建一个宏,如下所示:Overloading Macro on Number of Arguments,但这适用于我的情况。这个网站上的宏只适用于带有一个参数的#define,我的有两个。

这是我目前拥有的:

#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
#define TEST_MACRO(...)     GET_MACRO(__VA_ARGS__, _TEST_MACRO_8, _TEST_MACRO_7, _TEST_MACRO_6, _TEST_MACRO_5, _TEST_MACRO_4, _TEST_MACRO_3, _TEST_MACRO_2, _TEST_MACRO_1) (__VA_ARGS__)

#define _TEST_MACRO_8(letter1, number1, letter2, number2, letter3, number3, letter4, number4, letter5, number5, letter6, number6, letter7, number7, letter8, number8)           (PORT##letter1 |= ((1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5) | (1 << number6) | (1 << number7) | (1 << number8))
#define _TEST_MACRO_7(letter1, number1, letter2, number2, letter3, number3, letter4, number4, letter5, number5, letter6, number6, letter7, number7)         (PORT##letter1 |= ((1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5) | (1 << number6) | (1 << number7))
#define _TEST_MACRO_6(letter1, number1, letter2, number2, letter3, number3, letter4, number4, letter5, number5, letter6, number6)           (PORT##letter1 |= ((1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5) | (1 << number6))
#define _TEST_MACRO_5(letter1, number1, letter2, number2, letter3, number3, letter4, number4, letter5, number5)         (PORT##letter1 |= ((1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5))
#define _TEST_MACRO_4(letter1, number1, letter2, number2, letter3, number3, letter4, number4)           (PORT##letter1 |= ((1 << number1) | (1 << number2) | (1 << number3) | (1 << number4))
#define _TEST_MACRO_3(letter1, number1, letter2, number2, letter3, number3)         (PORT##letter1 |= ((1 << number1) | (1 << number2) | (1 << number3))
#define _TEST_MACRO_2(letter1, number1, letter2, number2)           (PORT##letter1 |= ((1 << number1) | (1 << number2))
#define _TEST_MACRO_1(letter1, number1)         (PORT##letter1 |= (1 << number1))

如果我这样做:

#define ONE    D, 0
#define TWO    D, 1
#define THREE  D, 2

TEST_MACRO(ONE); //Error: macro _TEST_MACRO_2 requires 4 arguments but only 2 given
TEST_MACRO(ONE,TWO); //Error: macro _TEST_MACRO_4 requires 8 arguments but only 4 given
TEST_MACRO(ONE,TWO,THREE); //Error: macro _TEST_MACRO_6 requires 12 arguments but only 6 given

这里有什么问题?我该如何解决?

最好的问候!

编辑:

为了澄清一点,这里是使用它的背景。我正在编写一个 8 位 AVR 微控制器。并且知道我有这样定义的引脚:#define PIN1 A,0,其中 A 代表 PIN 字母,0 代表 PIN 编号。

如果我以这种方式定义了一大堆,当我想更改它们的某些设置时,我必须一个一个地手动进行,例如:PIN_HIGH(PIN1);PIN_HIGH(PIN2);PIN_HIGH(PIN3),并且更多的,代码得到很乱。

所以我正在寻找一种方法来使用一个宏:PIN_HIGH(PIN1,PIN2,PIN3);。当我将PIN1,PIN2,PIN3 字母传递给宏时,它们匹配也很重要,因为有时我可以将图钉移到其他字母。

非常欢迎任何有关如何完成此任务的建议!

【问题讨论】:

  • 我想不出更好的方法...任何改进都非常受欢迎!
  • 它更容易阅读:PIN_HIGH(PIN_1,PIN_2,PIN_8);比 PORTA |= ((1
  • 我敢肯定,您可以比第二个示例更干净,而且几乎任何事情都比不得不猜测实际扩展的宏要好。但正如我所说,我不会成为使用它的人,所以显然这是你的决定。但是,您确实问过了。 :-)
  • #define D, 0 是定义宏的一种奇怪方式。宏名是D,是展开的第一个记号。为什么不插入空格? #define D , 0
  • 对不起,这是一个错字。我的意思是#define PIN D,0

标签: c macros


【解决方案1】:

表示端口的字符除了第一个之外不使用。所以,我建议采用以下方式。

#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
#define TEST_MACRO(letter,...)  (PORT##letter |=  GET_MACRO(__VA_ARGS__, _TEST_MACRO_8, _TEST_MACRO_7, _TEST_MACRO_6, _TEST_MACRO_5, _TEST_MACRO_4, _TEST_MACRO_3, _TEST_MACRO_2, _TEST_MACRO_1) (__VA_ARGS__) )

#define _TEST_MACRO_8(number1, number2, number3,  number4,  number5,  number6,  number7, number8) \
    (1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5) | (1 << number6) | (1 << number7) | (1 << number8)
#define _TEST_MACRO_7(number1, number2, number3,  number4,  number5,  number6,  number7)\
    (1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5) | (1 << number6) | (1 << number7)
#define _TEST_MACRO_6(number1, number2, number3,  number4,  number5,  number6)\
    (1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5) | (1 << number6)
#define _TEST_MACRO_5(number1, number2, number3,  number4,  number5)\
    (1 << number1) | (1 << number2) | (1 << number3) | (1 << number4) | (1 << number5)
#define _TEST_MACRO_4(number1, number2, number3,  number4)\
    (1 << number1) | (1 << number2) | (1 << number3) | (1 << number4)
#define _TEST_MACRO_3(number1, number2, number3)\
    (1 << number1) | (1 << number2) | (1 << number3)
#define _TEST_MACRO_2(number1, number2)\
    (1 << number1) | (1 << number2)
#define _TEST_MACRO_1(number1)\
    (1 << number1)


TEST_MACRO(D, 1);
TEST_MACRO(D, 0, 1);
TEST_MACRO(D, 0, 1, 2);

#define ONE    (D, 0)
#define TWO    (D, 1)
#define THREE  (D, 2)
#define CAR(a,b) a
#define CDR(a,b) b
#define F(x) CAR x
#define R(x) CDR x 
#define TEST_MACRO_WRAP(...) TEST_MACRO(__VA_ARGS__)
TEST_MACRO_WRAP(F(ONE), R(ONE));
TEST_MACRO_WRAP(F(ONE), R(ONE), R(TWO));
TEST_MACRO_WRAP(F(ONE), R(ONE), R(TWO), R(THREE));

【讨论】:

  • 我真的很喜欢这个,但是有没有办法传递整个 ONE, TWO, THREE #defines不必传递其中的一部分,例如来自 ONE 的字母和数字,然后只传递来自 TWO 的数字。然后,如果传递的所有字母都相同,是否可以检查宏,如果不是则抛出#error?谢谢!
  • 这项检查是否所有字母都相同必须在编译时完成,因为我可用的资源非常有限。再次感谢您!
  • @user1806687 无法在预处理器中比较非数字的相等性。
  • 我不知道这是否有任何区别,但字母是枚举的一部分:typedef enum PIN_LETTERS { A, B, C, D } letters_t;
  • @user1806687 您不能在预处理器中直接使用 C 程序中定义的类型或变量。可以嵌入代码,但如果它可以定义为函数。也不编译时检查。
【解决方案2】:

ONETWOTHREE 都在扩展 TEST_MACRO 之前立即扩展,因此当您说 TEST_MACRO(ONE) 时,__VA_ARGS__ 宏 arg 设置为 D, 0(扩展ONE),这意味着你调用_TEST_MACRO_2,因为这是两个参数。

由于您总是需要偶数个参数,您可以将TEST_MACRO 定义为:

#define TEST_MACRO(...)     GET_MACRO(__VA_ARGS__, _TEST_MACRO_4, ERROR, _TEST_MACRO_3, ERROR, _TEST_MACRO_2, ERROR, _TEST_MACRO_1, ERROR) (__VA_ARGS__)
#define ERROR(...)    #error "Odd number of arguments to TEST_MACRO"

【讨论】:

  • 我明天会试一试,然后告诉你。因为这里很晚,我住的地方。
猜你喜欢
  • 2023-04-11
  • 2012-07-30
  • 2019-05-20
  • 2013-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-31
相关资源
最近更新 更多