【问题标题】:Is it possible to put a preprocessor conditional inside a C macro?是否可以在 C 宏中放置条件预处理器?
【发布时间】: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(_,_) 使用单独的宏。
  • 那么你是在尝试实现一种重载形式。也许您应该研究可变参数宏。看到这个问题stackoverflow.com/questions/3420459/…
  • @TheodorosChatzigiannakis:问题是我需要重载传递宏的值,而不是参数的数量。

标签: c macros


【解决方案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;
    

    【讨论】:

      猜你喜欢
      • 2011-07-05
      • 2010-09-23
      • 2011-04-16
      • 2020-09-18
      • 2010-11-15
      • 2020-02-09
      • 2018-05-08
      • 2015-04-05
      • 2011-01-26
      相关资源
      最近更新 更多