检查C预处理器列表中是否存在条目

时间:2018-02-27 02:30:04

标签: c c-preprocessor x-macros

是否可以检查X-macro定义的列表中是否存在条目?鉴于下面的示例代码,我希望#if defined(GEORGE)条件为真。

编辑:当然没有明确#define GEORGE。我希望有办法检查列表中的条目(在预处理器中),我只想在列表中进行声明。我想这可能是不可能的。

谢谢!

#include <stdio.h>

#define NAMES \
X( JOHN, "John Adams" ) \
X( GEORGE, "George Washington" ) \
X( ABRAHAM, "Abraham Lincoln ")

#define X(_id, _name)    _id,
typedef enum {
    NAMES
} names_e;
#undef X

typedef struct {
    char *name;
} names_t;

#define X(_id, _name)    [_id] = { .name = _name },
static names_t const names[] = {
    NAMES
};
#undef X

int main(void) {
    int i;

    for (i=0; i < sizeof(names)/sizeof(names[0]); i++) {
        printf("%s\n", names[i].name);
    }

    printf("names[ABRAHAM] = %s\n", names[ABRAHAM].name);

#if defined(GEORGE)
    printf("names[GEORGE] = %s\n", names[GEORGE].name);
#endif

    return 0;
}

输出

John Adams
George Washington
Abraham Lincoln 
names[ABRAHAM] = Abraham Lincoln 

2 个答案:

答案 0 :(得分:0)

不幸的是,你不能在宏体内编写宏,所以使用你已经获得的轮廓管理它会很棘手(我没有办法实现它)。

您只能测试预处理器中的宏(而不是枚举元素的名称),并且您无法通过预处理器编写宏(Id无法有效地生成基于#define的新值在它的论点上),所以你必须做一些咕噜咕噜的工作。

如果你定义

#define

然后你可以使用:

#define P_JOHN 0
#define P_GEORGE 1
#define P_ABRAHAM 2

请注意,您有责任确保#define NAMES \ X( JOHN, "John Adams" ) \ X( GEORGE, "George Washington" ) \ X( ABRAHAM, "Abraham Lincoln ") #define X(_id, _name) _id = P_ ## _id, // Crucial change typedef enum { NAMES } names_e; #undef X typedef struct { char *name; } names_t; #define X(_id, _name) [_id] = { .name = _name }, static names_t const names[] = { NAMES }; #undef X int main(void) { int i; for (i=0; i < sizeof(names)/sizeof(names[0]); i++) { printf("%s\n", names[i].name); } printf("names[ABRAHAM] = %s\n", names[ABRAHAM].name); #if defined(P_GEORGE) // Crucial change printf("names[GEORGE] = %s\n", names[GEORGE].name); #endif return 0; } 名称具有唯一编号(我不确定您将如何处理George HW Bush和George W Bush - 似乎有与那里的乔治华盛顿发生冲突。

示例输出:

P_*

答案 1 :(得分:0)

您可以尝试使用预处理器模式匹配器。这个概念只需要一个间接的SECOND宏; GLUE非常适合推送任意前缀:

#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B

#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(A,B,...) B

...以及X宏&#34;列&#34;仅包含&#34;伪标识符&#34;:

#define NAMES \
X( JOHN, "John Adams" ) \
X( GEORGE, "George Washington" ) \
X( ABRAHAM, "Abraham Lincoln ")

......你可以这样做:

#define X(ID_, NAME_) SECOND(GLUE(SEARCH_FOR_,ID_),+0)
#define SEARCH_FOR_GEORGE ,+1
#if NAMES
printf("names[GEORGE] = %s\n", names[GEORGE].name);
#endif
#undef SEARCH_FOR_GEORGE
#define SEARCH_FOR_THOMAS ,+1
#if NAMES
#error Dewey wins!
#endif
#undef SEARCH_FOR_THOMAS
#undef X

这是有效的,因为SECOND 间接扩展到第二个参数;因此默认情况下SECOND(GLUE(SEARCH_FOR,ID_),+0)会扩展为+0;任何+0链都是有效的虚假表达。但是因为扩展的间接,第一个参数是粘贴的令牌,那么如果你将粘贴的令牌SEARCH_FOR_GEORGE定义为自己用逗号扩展,则逗号之后的表达式成为新的第二个参数。 (问我是否需要这个在Microsoft VS预处理器上工作;这需要微小的调整)。