预处理器失败的原因是 - '#'后面没有宏参数

lor*_*hog 10 c macros

我试图简化数组的声明,但遇到了我正在使用的预处理器的问题.我的初始代码如下所示:

#define REQ_ENTRY(parm_1, parm_2)    \
#if defined(parm_1)                  \
    { parm_1, parm_2 },              \
#endif

typedef struct {
    int parm1,
        parm2;
} MyTypedef_t;

static const MyTypedef_t MyList[] =
{
    REQ_ENTRY( ID_1, 1 )
    REQ_ENTRY( ID_2, 2 )
    REQ_ENTRY( ID_3, 3 )
    REQ_ENTRY( ID_4, 4 )
    REQ_ENTRY( ID_5, 5 )
};
Run Code Online (Sandbox Code Playgroud)

当然,构建失败,错误消息为"错误:'#'后面没有宏参数".这里解释了这个原因(为什么编译器抱怨这个宏声明)

基本上,我试图避免将数组声明为如下,这确实有效:

static const MyTypedef_t MyList[] =
{
    #if defined (ID_1)
    { ID_1, 1 },
    #endif

    #if defined (ID_2)
    { ID_2, 2 },
    #endif

    #if defined (ID_3)
    { ID_3, 3 },
    #endif

    #if defined (ID_4)
    { ID_4, 4 },
    #endif

    #if defined (ID_5)
    { ID_5, 5 },
    #endif        
};
Run Code Online (Sandbox Code Playgroud)

该列表可能相当长,并根据项目的构建类型而有所不同.我曾尝试过使用x-macros,但我想我会遇到同样的问题.我希望有人可能会看到一种方法来创建预处理器宏,以便我可以实现原始的糖语法?非常感谢任何见解.

ric*_*ici 6

没有好的解决方案。但是,存在各种变化的解决方案。

如果您不介意在宏定义中同时包含id序列,则可以这样解决:

#define CONCAT2(x,y) x##y
#define CONCAT(x,y) CONCAT2(x,y)
#define REQ_ENTRY_YES(p1, p2) { p1 , p2 }
#define REQ_ENTRY_NO(p1) 
#define IS_PAIR_HELPER(a, b, c, ...) c
#define IS_PAIR(...) IS_PAIR_HELPER(__VA_ARGS__, YES, NO)
#define REQ_ENTRY(pair) CONCAT(REQ_ENTRY_, IS_PAIR(pair))(pair)

#define ID_1 78723649, 1
#define ID_3 2347602, 3

typedef struct {
    int parm1,
        parm2;
} MyTypedef_t;

static const MyTypedef_t MyList[] =
{
    REQ_ENTRY( ID_1 )
    REQ_ENTRY( ID_2 )
    REQ_ENTRY( ID_3 )
    REQ_ENTRY( ID_4 )
    REQ_ENTRY( ID_5 )
};
Run Code Online (Sandbox Code Playgroud)

使用来运行gcc -std=c11 -Wall -E,并仅显示MyList定义:

static const MyTypedef_t MyList[] =
{
    { 78723649 , 1 }

    { 2347602 , 3 }


};
Run Code Online (Sandbox Code Playgroud)

您可以通过使用宏中的任何第二个值来执行相同的操作#define ID_x,只要有一个即可。实际参数可以添加到中REQ_ENTRY。但这需要一些额外的杂耍。


M O*_*ehm 5

遗憾的是,该defined运算符仅在#ifand的上下文中可用#ifelse,而不适用于宏扩展。就目前而言,我同意rici关于各种丑陋的解决方案。

这是一个解决方案,需要将定义的值用括号括起来。然后,您可以使用 ID 作为常规值,也可以将其传递给DEF,当宏在括号中时扩展为 1,否则扩展为 0。(这是我在这里学到的一个技巧。)

DEF宏的帮助下,您可以创建扩展或忽略给定定义的辅助宏:

/* Auxiliary macros */

#define M_CHECK(...) M_CHECK_(__VA_ARGS__)
#define M_CHECK_(a, b, ...) b

#define M_IS_PAREN(x) M_CHECK(M_IS_PAREN_ x, 0)
#define M_IS_PAREN_(...) 1, 1

#define M_CONCAT(a, b) M_CONCAT_(a, b)
#define M_CONCAT_(a, b) a ## b

/* Conditional definition macros */

#define DEF(x) M_IS_PAREN(x)

#define DEF_IF_0(id, def)
#define DEF_IF_1(id, def) {id, def},

#define COND_DEF(x, y) M_CONCAT(DEF_IF_, DEF(x))(x, y)

/* Implementation */

#define ID_1 (27)
#define ID_3 (28)
#define ID_4 (29)

static const MyTypedef_t MyList[] = {
    COND_DEF(ID_1, 1)
    COND_DEF(ID_2, 2)
    COND_DEF(ID_3, 3)
    COND_DEF(ID_4, 4)
    COND_DEF(ID_5, 5)
};
Run Code Online (Sandbox Code Playgroud)

这将产生:

static const MyTypedef_t MyList[] = {
    {(27), 1},

    {(28), 3},
    {(29), 4},

};
Run Code Online (Sandbox Code Playgroud)

您还可以DEF在代码中使用宏,它将被扩展为 0 或 1:

printf("ID_1 is %s.\n", DEF(ID_1) ? "defined" : "undefined");
Run Code Online (Sandbox Code Playgroud)