是否可以在 C 宏中放置条件预处理器?

Posted

技术标签:

【中文标题】是否可以在 C 宏中放置条件预处理器?【英文标题】:Is it possible to put a preprocessor conditional inside a C macro? 【发布时间】:2013-09-25 17:02:31 【问题描述】:

有没有办法编写一个 C 预处理器宏,根据它收到的参数扩展为不同的东西?

#define foo() ???

/* 1 */
foo(name)

/* 2 */
foo(_)

想要的结果:

/* 1 */
int name;

/* 2 */
/*ignore*/

是的,我知道宏是邪恶的。我问这个主要是出于好奇。

【问题讨论】:

宏太棒了。 您能否解释一下目的,或者举一个更好的例子?该参数必须在编译时固定,这意味着您也可以使用两个不同的宏名称。 @mbratch:在这种特殊情况下,我使用宏来定义一组变量,但有些变量是可选的,我想避免定义它们。由于组合爆炸,多个宏名称无法正常工作:对于两个变量名称,我需要为 foo(a,b)foo(a,_)foo(_,b)foo(_,_) 使用单独的宏。 那么你是在尝试实现一种重载形式。也许您应该研究可变参数宏。看到这个问题***.com/questions/3420459/… @TheodorosChatzigiannakis:问题是我需要重载传递宏的值,而不是参数的数量。 【参考方案1】:

要扩展 Gavin Smith 的答案,您实际上可以检查宏扩展中的条件:

#define FOO_name 1
#define FOO__ 0

#define CONC(a,b) a##_##b

#define IF(c, t, e) CONC(IF, c)(t, e)
#define IF_0(t, e) e
#define IF_1(t, e) t

#define FOO(x) IF(CONC(FOO,x), int x;, )

FOO(name) // -> int name;
FOO(_)    // -> /*nothing*/

如果您喜欢冒险,可以使用辅助宏轻松扩展 IF 以允许逗号、抑制宏扩展等。

如上所述,但这确实需要您提前知道所有所需的名称。

【讨论】:

【参考方案2】:

也许尝试一些多阶段的宏扩展?这是Boost preprocessor/control/if library使用的策略。

#define FOO_NAME 1
#define FOO__ 2

#define CONC(a,b) a##_##b
#define FOO(x) CONC(FOO,x)

我认为没有任何方法可以检查 C 宏扩展中的条件。

我能想到的最好的办法是使用# 字符串化运算符将宏参数转换为字符串文字,然后使用运行时函数进行检查。 (不过,这不适用于您想要输出变量声明的情况。)

例如,以下打印“011”:

#define FOO(x) (strcmp("NAME", #x) ? 1 : 0)

main()

    printf("%d", FOO(NAME));
    printf("%d", FOO(1));
    printf("%d", FOO(2));

编译器可能会在编译时优化strcmp 比较,因此它不会比如果有真正的预处理器条件可用时效率更低。但是,将FOO 设为普通函数会更清晰,并且可能同样有效。

【讨论】:

有趣的把戏!但是有没有一种方法我不需要列举“1”案例的所有可能性?例如,如果它是_,那么宏会产生 2,如果它的其他任何东西产生 1? 我用有限的解决方法更新了我的答案,该解决方法不适用于您的原始问题。 不幸的是,我不能在我的案例中使用运行时测试。我开始认为你的第一个解决方案是我能得到的最好的解决方案。 @hugomg 你想要的都是可能的,但是它需要很多肮脏的预处理技巧:github.com/pfultz2/Cloak/wiki/…我会添加一个答案【参考方案3】:

使用here 描述的技巧,可以在编译时做你想做的事。

您可以使用文档末尾定义的EQUAL 宏,然后执行以下操作:

#define COMPARE__(x) x
#define OPTION_0(x) int x;
#define OPTION_1(x) /* nothing */
#define foo(x) CAT(OPTION_, EQUAL(_, x))(x)

foo(name1) // int name1;
foo(_)     // /* nothing */
foo(name2) // int name2;

【讨论】:

以上是关于是否可以在 C 宏中放置条件预处理器?的主要内容,如果未能解决你的问题,请参考以下文章

预处理器中的 C# 宏定义

使用 Boost/Wave C/C++ 预处理器的选择性宏扩展

使用预处理器宏进行条件编译 Xcode

C语言_宏

C 预处理器宏参数在末尾带有空格以进行连接?

笔记2:预处理器-预处理指令