C语言 如何使 #if #endif 成为宏的一部分


#define M(N)
#if N == 5
    /*several lines of code that 
      Can't be replaced with a   
      tertnary operator*/
#else
    N;
#endif

当我像这样使用这个宏时

M(5);

我希望输出是

// everything within the #if #else block

但它不编译。

我不惊讶它不编译:我知道 #if 不能在延续行即"\"上使用。

我也试过

#define POUND_IF #if

然后使用POUND_IF但不起作用。

这可能做到吗?

是否有一些漂亮的 Boost 预处理器可以使用的东西?

简而言之,你不能。不过,您可以改为依赖优化器:

#define M(N)
    do { if (N == 5) { 
    /*several lines of code that 
      Can't be replaced with a   
      ternary operator*/ 
    } else { N; } } while (0)

如果编译器可以确定代码运行时N的值将为 5(例如,您编写 M(5) (,则只有if正文中的代码将包含在生成的代码中。 如果编译器可以确定运行代码时 N 的值不会为 5,则它将仅生成 else 子句正文中的代码。 如果它无法确定值是什么,预处理器也无法这样做,但编译器将包含所有代码。

定义不能包含预处理器指令(任何以 # 开头的内容(。

有条件地扩展到某些值需要相当复杂的宏学,并且可能并不总是按照您想要的方式工作。上面的例子可以写成这样:

#define ONE_OR_TWO(...) ONE_OR_TWO_(__VA_ARGS__, 2, 1,)
#define ONE_OR_TWO_(_1, _2, X, ...) X
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A ## B
#define M(N) CAT(IF_, ONE_OR_TWO(CAT(IS_, N)))({
    code; 
    code; 
}, N)
#define IS_5 ,
#define IF_1(A, B) B
#define IF_2(A, B) A
M(5);  //-> { code; code; }
M(8);  //-> 8

不过,这是非常脆弱的。例如,您只能使用某些类型的表达式作为参数来M - 它们必须具有允许连接的语法结构,并且没有展开的逗号 - 并且它仅适用于预定值(例如,使用此方法无法与比简单数字更复杂的东西进行比较,因为您无法从更复杂的表达式中构建宏名称(。

但原则上,这是可以做到的。您只需要成千上万行宏定义来涵盖一组有用的情况,而不是像这样的琐碎情况。你可以通过使用像Order-PP或Boost.Preprocessor这样的元编程库来获得这些,但是如果你在语法上稍微失误,也要为晦涩的错误消息做好准备。

最新更新