“#define X X”是什么意思?

37

在Linux头文件epoll.h中,我找到了以下代码:

enum EPOLL_EVENTS
{
    EPOLLIN = 0x001,
#define EPOLLIN EPOLLIN
...
}

#define EPOLLIN EPOLLIN是什么意思?


12
可能需要处理具有 #ifdef EPOLLIN 的代码,以检查是否已定义该宏。 - tadman
3
"May be" 应该用于像 #if EPOLLIN 这样的句子中。如果你使用了 #define EPOLLIN,那么只能与 #ifdef 一起使用。 - Eduardo Pascual Aseff
仅限于您的头衔,glibc的stdio.h也使用类似的技巧来处理stdoutstdinstderr,但其目的不同:使标准满意。 - Giovanni Cerretani
1
我的猜测是,在将它们放入“枚举”之前,最初只有#define EPOLLIN 0x001等内容,并且这保留了依赖于定义的代码的向后兼容性。 - Bergi
1
@Berge 是的,就是这样。在其他C库中,这些宏直接扩展为数字常量。Glibc希望使用枚举来设置值,因为这使得符号名称对调试器可用,但ISO C要求它们是预处理器宏,所以这是一种既有利又有弊的方法。 - zwol
哦,等等,我们这里不是在讨论errno代码。那么,这种enum+define的技巧最初是为了errno代码开发的,因为ISO C确实对此有要求,现在它被用于glibc大多数符号常量,因为无论CONSTANT是什么,能够做到#ifdef CONSTANT真的非常方便。同时,在调试器中使用CONSTANT也很方便。 - zwol
2个回答

30

这将创建一个名为EPOLLIN的宏,其替换文本也是EPOLLIN

这很可能是预处理器检查可用事件代码并根据需要有条件地编译代码的一种方式。如果我们转到glibc的git库并查看git blame的输出,我们将看到对于enum EPOLL_EVENTS的以下内容:

ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  34) enum EPOLL_EVENTS
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  35)   { 
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  36)     EPOLLIN = 0x001,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  37) #define EPOLLIN EPOLLIN
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  38)     EPOLLPRI = 0x002,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  39) #define EPOLLPRI EPOLLPRI
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  40)     EPOLLOUT = 0x004,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  41) #define EPOLLOUT EPOLLOUT
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  42)     EPOLLRDNORM = 0x040,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  43) #define EPOLLRDNORM EPOLLRDNORM
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  44)     EPOLLRDBAND = 0x080,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  45) #define EPOLLRDBAND EPOLLRDBAND
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  46)     EPOLLWRNORM = 0x100,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  47) #define EPOLLWRNORM EPOLLWRNORM
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  48)     EPOLLWRBAND = 0x200,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  49) #define EPOLLWRBAND EPOLLWRBAND
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  50)     EPOLLMSG = 0x400,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  51) #define EPOLLMSG EPOLLMSG
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  52)     EPOLLERR = 0x008,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  53) #define EPOLLERR EPOLLERR
5e826ab5 (Ulrich Drepper 2003-03-25 01:14:36 +0000  54)     EPOLLHUP = 0x010,
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  55) #define EPOLLHUP EPOLLHUP
94833f11 (Ulrich Drepper 2007-10-28 01:34:10 +0000  56)     EPOLLRDHUP = 0x2000,
94833f11 (Ulrich Drepper 2007-10-28 01:34:10 +0000  57) #define EPOLLRDHUP EPOLLRDHUP
981569c7 (Joseph Myers   2016-03-14 19:04:53 +0000  58)     EPOLLEXCLUSIVE = 1u << 28,
981569c7 (Joseph Myers   2016-03-14 19:04:53 +0000  59) #define EPOLLEXCLUSIVE EPOLLEXCLUSIVE
f8d44fdc (Andreas Jaeger 2012-07-26 13:11:33 +0200  60)     EPOLLWAKEUP = 1u << 29,
f8d44fdc (Andreas Jaeger 2012-07-26 13:11:33 +0200  61) #define EPOLLWAKEUP EPOLLWAKEUP
4920765e (Ulrich Drepper 2011-12-21 22:14:05 -0500  62)     EPOLLONESHOT = 1u << 30,
e11676dd (Ulrich Drepper 2004-01-21 06:23:26 +0000  63) #define EPOLLONESHOT EPOLLONESHOT
4920765e (Ulrich Drepper 2011-12-21 22:14:05 -0500  64)     EPOLLET = 1u << 31
5e826ab5 (Ulrich Drepper 2003-03-25 01:14:36 +0000  65) #define EPOLLET EPOLLET
ad3bf20c (Ulrich Drepper 2002-12-16 23:38:42 +0000  66)   };

从这里可以看出,大多数这些事件是在2002年创建的,但后来添加了一些其他事件。因此,这些宏允许您按如下方式检查特定标志是否可用:

从这里可以看出,大部分事件都是在2002年创建的,但之后还增加了一些。因此,使用这些宏可以按照以下方式检查特定标志是否可用:

#ifdef EPOLLEXCLUSIVE 
/* code that can handle EPOLLEXCLUSIVE */
#else
/* code that uses an alternate event */
#endif

这样就可以在拥有新事件的更新Linux版本上运行代码,也可以在不支持新事件的旧版本上运行。


1
为此,#define EPOLLIN 不就足够了吗? - DYZ
13
如果这样做,那么枚举将无法编译,因为预处理器会将EPOLLIN枚举成员替换为空字符串。 - dbush
1
@dbush DYZ 我认为DYZ的建议是他们做#ifdef EPOLLIN_SUPPORTED,然后使用EPOLLIN而不是定义一个同名符号的宏。 - Allison

7

#define EPOLLIN EPOLLIN

这个定义将预处理宏EPOLLIN定义为EPOLLIN

这很可能是为了后续的#ifdef EPOLLIN检查而定义的。


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