我指的是来自开源项目 tig 的代码示例。这是一个很棒的工具!
文件:tig.c
我很难找到定义请求枚举的理由,如下所示:
enum request {
#define REQ_GROUP(help)
#define REQ_(req, help) REQ_##req
/* Offset all requests to avoid conflicts with ncurses getch values. */
REQ_UNKNOWN = KEY_MAX + 1,
REQ_OFFSET,
REQ_INFO,
/* Internal requests. */
REQ_JUMP_COMMIT,
#undef REQ_GROUP
#undef REQ_
};
甚至结构......
static const struct request_info req_info[] = {
#define REQ_GROUP(help) { 0, NULL, 0, (help) },
#define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) }
REQ_INFO
#undef REQ_GROUP
#undef REQ_
};
可以看出REQ_GROUP
多次被#defined引起混淆..至少对我而言。我知道可能有一个很好的理由这样做..使用宏隐藏代码中的枚举/结构定义的实际原因是什么?
答案 0 :(得分:7)
当在同一数据源上使用不同的处理时,这通常会失效。
例如,您可以这样做:
#define MY_LIST X(Elem1) X(Elem2) X(Elem3)
然后:
enum MyEnum {
# define X(e) e,
MY_LIST
Last
# undef X
};
在这种情况下,使用MY_LIST
的当前定义展开X
。
现在,在同一个文件中,我还可以使用MY_LIST
创建to_string
方法
char const* to_string(MyEnum e) {
switch(e) {
# define X(e) case e: return #e;
MY_LIST
case Last: return "Last";
# undef X
}
return 0;
} // to_string
这样,enum的值集只能写一次,并且enum和处理它的一些方法都会自动与这个集保持同步。
答案 1 :(得分:1)
这是为了避免重复请求列表。该列表只需要在一个地方维护,REQ_INFO
的定义,并通过REQ_GROUP
和REQ_
的适当定义从该列表自动生成枚举和数据结构。
如果没有这些宏,枚举和数据结构必须单独维护,注意保持它们彼此一致,涉及更多的工作和更多的错误范围。
答案 2 :(得分:1)
您错过了同一档案中的重要定义:
#define REQ_INFO \
REQ_GROUP("View switching") \
VIEW_INFO(VIEW_REQ), \
\
REQ_GROUP("View manipulation") \
REQ_(ENTER, "Enter current line and scroll"), \
REQ_(NEXT, "Move to next"), \
REQ_(PREVIOUS, "Move to previous"), \
< output omitted as it is too long >
因此,例如,您展示的结构扩展为:
static const struct request_info req_info[] = {
{ 0, NULL, 0, "View switching" },
< VIEW_INFO also expands to some long structure that was ommited here >
{ 0, NULL, 0, "View manipulation" },
{ REQ_ENTER, ENTER, STRING_SIZE("ENTER"), "Enter current line and scroll"},
{ REQ_NEXT, NEXT, STRING_SIZE("NEXT"), "Move to next"}
< and so on >
};
正如其他提到的答案,主要是为了保持多个结构/枚举器同步。