检查 C 预处理器列表中是否存在条目
Check existence of an entry in C pre-processor list
是否可以检查 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
不幸的是,你不能在宏体内写宏,所以用你的大纲来管理它会很棘手(我没有找到实现它的方法)。
您只能在预处理器中测试宏(不是枚举元素的名称),并且不能通过预处理器编写宏(#define
不能有用地生成新的 #define
基于它的论点),所以你必须做一些 grunt-work.
如果你定义
#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;
}
请注意,您有责任确保 P_*
名称具有唯一编号(而且我不确定您打算如何处理乔治 H W 布什和乔治 W 布什 — 似乎在那里与乔治华盛顿发生冲突)。
示例输出:
John Adams
George Washington
Abraham Lincoln
names[ABRAHAM] = Abraham Lincoln
names[GEORGE] = George Washington
您可以尝试使用预处理器模式匹配器。这个概念只需要一个 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
...对于仅包含 "pseudo-identifiers":
的 X 宏 "column"
#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 预处理器上工作;这需要一个小的调整)。
是否可以检查 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
不幸的是,你不能在宏体内写宏,所以用你的大纲来管理它会很棘手(我没有找到实现它的方法)。
您只能在预处理器中测试宏(不是枚举元素的名称),并且不能通过预处理器编写宏(#define
不能有用地生成新的 #define
基于它的论点),所以你必须做一些 grunt-work.
如果你定义
#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;
}
请注意,您有责任确保 P_*
名称具有唯一编号(而且我不确定您打算如何处理乔治 H W 布什和乔治 W 布什 — 似乎在那里与乔治华盛顿发生冲突)。
示例输出:
John Adams
George Washington
Abraham Lincoln
names[ABRAHAM] = Abraham Lincoln
names[GEORGE] = George Washington
您可以尝试使用预处理器模式匹配器。这个概念只需要一个 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
...对于仅包含 "pseudo-identifiers":
的 X 宏 "column"#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 预处理器上工作;这需要一个小的调整)。