的价值RTNLGRP_NEIGH
将为 3。您可以使用以下程序轻松测试这一点。
#include <stdio.h>
/* RTnetlink multicast groups */
enum rtnetlink_groups {
RTNLGRP_NONE,
#define RTNLGRP_NONE RTNLGRP_NONE
RTNLGRP_LINK,
#define RTNLGRP_LINK RTNLGRP_LINK
RTNLGRP_NOTIFY,
#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
RTNLGRP_NEIGH,
#define RTNLGRP_NEIGH RTNLGRP_NEIGH
RTNLGRP_TC,
#define RTNLGRP_TC RTNLGRP_TC
RTNLGRP_IPV4_IFADDR,
#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
/* ... */
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
RTNLGRP_PHONET_ROUTE,
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
int
main()
{
printf("RTNLGRP_NEIGH = %d\n", RTNLGRP_NEIGH);
}
它输出这个:
RTNLGRP_NEIGH = 3
由于每个宏都是#define
d 以自己的名字命名,RTNLGRP_NEIGH
in main
将被替换为RTNLGRP_NEIGH
。但由于扩展不是递归的,因此它会在此时停止并且程序使用enum
持续的RTNLGRP_NEIGH
这是第四个,因此值为 3。
如果您不确定预处理器的作用,您始终可以使用-E
切换并查看预处理的输出。编译上面的例子gcc -E
给出(未显示 840 行#include
d 标准库头文件)
# 4 "main.c"
enum rtnetlink_groups {
RTNLGRP_NONE,
RTNLGRP_LINK,
RTNLGRP_NOTIFY,
RTNLGRP_NEIGH,
RTNLGRP_TC,
RTNLGRP_IPV4_IFADDR,
RTNLGRP_PHONET_ROUTE,
__RTNLGRP_MAX
};
int
main()
{
printf("RTNLGRP_NEIGH = %d\n", RTNLGRP_NEIGH);
}
希望这不会那么令人困惑。
The #define
s 混入enum
定义没有影响enum
定义。在哪里并不重要#define
s 位于。它们可以(并且可能应该)放置在定义之前或之后。
/* RTnetlink multicast groups */
enum rtnetlink_groups {
RTNLGRP_NONE,
RTNLGRP_LINK,
RTNLGRP_NOTIFY,
RTNLGRP_NEIGH,
RTNLGRP_TC,
RTNLGRP_IPV4_IFADDR,
/* ... */
RTNLGRP_PHONET_ROUTE,
__RTNLGRP_MAX
};
#define RTNLGRP_NONE RTNLGRP_NONE
#define RTNLGRP_LINK RTNLGRP_LINK
#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
#define RTNLGRP_NEIGH RTNLGRP_NEIGH
#define RTNLGRP_TC RTNLGRP_TC
#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
/* ... */
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
他们编写这段奇怪代码的原因可能是他们想使用重构旧代码
#define RTNLGRP_NONE 0
#define RTNLGRP_LINK 1
#define RTNLGRP_NOTIFY 2
#define RTNLGRP_NEIGH 3
#define RTNLGRP_TC 4
#define RTNLGRP_IPV4_IFADDR 5
/* ... */
使用enum
反而。但是因为现有代码可能依赖于标识符是宏的事实(例如测试#ifdef RTNLGRP_NEIGH
)他们希望提供具有相同值的宏。但请注意,这种方法是有缺陷的,因为预处理器不知道常量的值,因此您无法执行以下操作#if RTNLGRP_NEIGH >= 3
你可以,有RTNLGRP_NEIGH
been #define
d to 3
字面上地。因此,本质上,他们的方法结合了使用宏(名称空间污染)和使用宏的缺点enum
s(在预处理时不可用)。
我以前见过的一个可能更有用的模式是#define
常量为实际整数。
enum rtnetlink_groups {
RTNLGRP_NONE
#define RTNLGRP_NONE 0
= RTNLGRP_NONE,
RTNLGRP_LINK
#define RTNLGRP_LINK 1
= RTNLGRP_LINK,
RTNLGRP_NOTIFY
#define RTNLGRP_NOTIFY 2
= RTNLGRP_NOTIFY,
RTNLGRP_NEIGH
#define RTNLGRP_NEIGH 3
= RTNLGRP_NEIGH,
RTNLGRP_TC
#define RTNLGRP_TC 4
= RTNLGRP_TC,
RTNLGRP_IPV4_IFADDR
#define RTNLGRP_IPV4_IFADDR 5
= RTNLGRP_IPV4_IFADDR,
/* ... */
};
它将被预处理为以下内容。
enum rtnetlink_groups {
RTNLGRP_NONE
= 0,
RTNLGRP_LINK
= 1,
RTNLGRP_NOTIFY
= 2,
RTNLGRP_NEIGH
= 3,
RTNLGRP_TC
= 4,
RTNLGRP_IPV4_IFADDR
= 5,
};
请注意,这里至关重要的是#define
s 混合到enum
定义,否则我们会得到无效代码,例如3 = 3,
而不是想要的RTNLGRP_NEIGH = 3
.
哦,请不要使用__RTNLGRP_MAX
作为标识符。 C 标准保留包含两个相邻下划线或以下划线开头后跟大写字母的名称。在您自己的代码中使用它们会导致未定义的行为。