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

时间:2015-10-31 02:02:49

标签: c macros

#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预处理器可以使用?

2 个答案:

答案 0 :(得分:6)

简洁地说,你做不到。不过,您可以依赖优化器:

#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子句正文中的代码。如果它无法确定该值是什么,预处理器也无法这样做,但编译器将包含所有代码。

答案 1 :(得分:5)

宏定义不能包含预处理程序指令(以println开头的任何内容)。

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

#

但这非常脆弱。例如,您只能使用某些类型的表达式作为#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 的参数 - 它们必须具有允许连接的语法结构,并且没有未包装的逗号 - 并且它仅适用于预定值(例如,用于比较使用此方法无法使用比简单数字更复杂的东西,因为您无法使用更复杂的表达式构建宏名称。)

但原则上可以做到。您只需要成千上万行宏定义来覆盖一组有用的案例,而不是像这样的普通案例。您可以使用Order-PPBoost.Preprocessor之类的元编程库来获取这些文件,但如果您在语法中略微下滑,请准备好应用于模糊的错误消息。