如何在C预处理器中的#define语句中使用#if语句?

66

我想编写一个宏,根据其参数的布尔值输出代码。所以说,DEF_CONST(true) 应该扩展为 const,而 DEF_CONST(false) 应该扩展为空。

显然下面的代码不起作用,因为我们不能在 #define 中再使用另一个预处理器:

#define DEF_CONST(b_const) \
#if (b_const) \
  const \
#endif

4
这有什么意义?你能给一个具体的例子吗?因为这似乎很奇怪... - Dean Harding
请参见https://dev59.com/xV7Va4cB1Zd3GeqPGRNQ。 - Rhubbarb
1
@DeanHarding 在您发表评论的时候还不存在,但_Generic是一个例子。您可能需要检查uintmax_t是否具有与unsigned long long不同的基础类型。 - 12431234123412341234123
2个回答

66

您可以使用宏令牌连接来模拟条件语句,方法如下:

#define DEF_CONST(b_const) DEF_CONST_##b_const
#define DEF_CONST_true const
#define DEF_CONST_false

那么,

/* OK */
DEF_CONST(true)  int x;  /* expands to const int x */
DEF_CONST(false) int y;  /* expands to int y */

/* NOT OK */
bool bSomeBool = true;       // technically not C :)
DEF_CONST(bSomeBool) int z;  /* error: preprocessor does not know the value
                                of bSomeBool */

此外,如GMan和其他人正确指出的那样,允许将宏参数传递给DEF_CONST本身:

#define DEF_CONST2(b_const) DEF_CONST_##b_const
#define DEF_CONST(b_const) DEF_CONST2(b_const)
#define DEF_CONST_true const
#define DEF_CONST_false

#define b true
#define c false

/* OK */
DEF_CONST(b) int x;     /* expands to const int x */
DEF_CONST(c) int y;     /* expands to int y */
DEF_CONST(true) int z;  /* expands to const int z */

您还可以考虑更简单的方法(虽然可能不太灵活):

#if b_const
# define DEF_CONST const
#else /*b_const*/
# define DEF_CONST
#endif /*b_const*/

以上有错别字,只是错过了编辑标记。应该是 #define DEF_CONST(b_const) CONCATENATE(DEF_CONST_, b_const) - GManNickG
2
是的 - token pasting或stringizing(“##”或“#”)预处理器运算符几乎总是需要一定程度的间接性才能按预期工作:http://stackoverflow.com/questions/1767683/c-programming-preprocessor-macros-as-tokens/1769037#1769037 - Michael Burr
有可能扩展这个功能,使其接受参数,就像在x宏中使用的那样吗? - tdihp
有可能扩展这个功能,使其接受参数,就像在x宏中使用的那样吗? - undefined

8
做成参数化宏有点奇怪。为什么不直接这样做呢:
#ifdef USE_CONST
    #define MYCONST const
#else
    #define MYCONST
#endif

然后你可以像这样编写代码:
MYCONST int x = 1;
MYCONST char* foo = "bar";

如果您使用定义了USE_CONST的编译选项(例如在makefile或编译器选项中通常会有-DUSE_CONST),则它将使用常量,否则它不会使用。 编辑:实际上我看到Vlad在他的答案末尾涵盖了该选项,所以给他点赞 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接