迷惑MACRO和枚举定义 [英] Confusing MACRO and enum definition
问题描述
我正在浏览一些Route netlink源代码。
我想知道RTNLGRP_NEIGH的价值是多少
来源: http:// lxr.free-electrons.com/source/include/linux/rtnetlink.h?v=2.6.35#L550
541 / * RTnetlink多播组* /
542枚举rtnetlink_groups {
543 RTNLGRP_NONE,
544 #define RTNLGRP_NONE RTNLGRP_NONE
545 RTNLGRP_LINK,
546 #define RTNLGRP_LINK RTNLGRP_LINK
547 RTNLGRP_NOTIFY,
548 #define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
549 RTNLGRP_NEIGH,
550 #define RTNLGRP_NEIGH RTNLGRP_NEIGH
551 RTNLGRP_TC,
552 #define RTNLGRP_TC RTNLGRP_TC
553 RTNLGRP_IPV4_IFADDR,
554 #define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
... ...
... ...
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
585 RTNLGRP_PHONET_ROUTE,
586 #define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
587 __RTNLGRP_MAX
588};
589 #define RTNLGRP_MAX(__RTNLGRP_MAX - 1)
这个枚举是什么#define 。
什么是 RTNLGRP_NEIGH 的值? 6 OR 3
谢谢
RTNLGRP_NEIGH
的值将为3.您可以使用以下程序轻松测试。
#include< stdio.h>
/ * RTnetlink多播组* /
枚举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\\\
,RTNLGRP_NEIGH );
}
输出:
RTNLGRP_NEIGH = 3
由于每个宏都是 #define
d到自己的名字, main
RTNLGRP_NEIGH
/ code>将被替换为 RTNLGRP_NEIGH
。但是由于扩展不是递归的,所以它将在此时停止,程序使用枚举
常量 RTNLGRP_NEIGH
第四个因此具有值3。
如果您不确定预处理器是什么,您可以随时使用 -E
切换并查看预处理的输出。使用 gcc -E
编译上述示例(不显示 #include
d标准库标题的840行)
#4main.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\\\
,RTNLGRP_NEIGH);
}
希望不要那么困惑。
#define
混合到枚举
定义中对枚举
定义。没有关系 #define
的位置。他们可能(也许应该)被放置在定义之前或之后。
/ * RTnetlink多播组* /
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
已经 #define
d到 3
。因此,本质上,他们的方法结合了使用宏(名称空间污染)与使用枚举
s(在预处理时间不可用)的缺点。 p>
我以前看过的一个更有用的模式是将
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,
/ * .. 。* /
};
将被预处理为以下。
枚举rtnetlink_groups {
RTNLGRP_NONE
= 0,
RTNLGRP_LINK
= 1,
RTNLGRP_NOTIFY
= 2,
RTNLGRP_NEIGH
= 3,
RTNLGRP_TC
= 4,
RTNLGRP_IPV4_IFADDR
= 5,
};
请注意,这里至关重要的是, #define
s混合到枚举
定义中,否则我们会得到无效代码,如 3 = 3,
而不是所需的 RTNLGRP_NEIGH = 3
。
哦,请不要使用 __RTNLGRP_MAX
作为标识符。包含两个相邻下划线或以下划线开头的名称后跟大写字母的名称由C标准保留。在自己的代码中使用它们会导致未定义的行为。
I was browsing some Route netlink source code.
I wanted to figure out what was the value of RTNLGRP_NEIGH
Source: http://lxr.free-electrons.com/source/include/linux/rtnetlink.h?v=2.6.35#L550
541 /* RTnetlink multicast groups */
542 enum rtnetlink_groups {
543 RTNLGRP_NONE,
544 #define RTNLGRP_NONE RTNLGRP_NONE
545 RTNLGRP_LINK,
546 #define RTNLGRP_LINK RTNLGRP_LINK
547 RTNLGRP_NOTIFY,
548 #define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
549 RTNLGRP_NEIGH,
550 #define RTNLGRP_NEIGH RTNLGRP_NEIGH
551 RTNLGRP_TC,
552 #define RTNLGRP_TC RTNLGRP_TC
553 RTNLGRP_IPV4_IFADDR,
554 #define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
... ...
... ...
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
585 RTNLGRP_PHONET_ROUTE,
586 #define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
587 __RTNLGRP_MAX
588 };
589 #define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
What is this enum with #define doing.
What will be the value of RTNLGRP_NEIGH? 6 OR 3
Thanks
The value of RTNLGRP_NEIGH
will be 3. You can easily test this with the following program.
#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);
}
It outputs this:
RTNLGRP_NEIGH = 3
Since each macro is #define
d to its own name, the RTNLGRP_NEIGH
in main
will be replaced by RTNLGRP_NEIGH
. But since the expansion is not recursive, it will stop at this point and the program use the enum
constant RTNLGRP_NEIGH
which is the fourth and therefore has value 3.
If you are not sure what the preprocessor does, you can always compile with the -E
switch and look at the pre-processed output. Compiling the above example with gcc -E
gives (not showing 840 lines of the #include
d standard library headers)
# 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);
}
which is hopefully much less confusing.
The #define
s mixed into the enum
definition have no effect to the enum
definition. It doesn't matter where the #define
s are located. They could (and probably should) have been placed before or after the definition.
/* 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)
The reason they wrote this weired code is probably that they wanted to refactor old code using
#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
/* ... */
to use an enum
instead. But because existing code might rely on the fact that the identifiers are macros (such as testing #ifdef RTNLGRP_NEIGH
) they wanted to provide macros with the same value. Note that this approach is flawed, however, because the preprocessor won't know the value of the constant so you cannot do things like #if RTNLGRP_NEIGH >= 3
which you could, had RTNLGRP_NEIGH
been #define
d to 3
literally. So, in essence, their approach combines the disadvantages of using macros (name-space pollution) with those of using enum
s (not available at pre-processing time).
A maybe more useful pattern I have seen before is to #define
the constants to actual integers.
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,
/* ... */
};
which will be pre-processed to the following.
enum rtnetlink_groups {
RTNLGRP_NONE
= 0,
RTNLGRP_LINK
= 1,
RTNLGRP_NOTIFY
= 2,
RTNLGRP_NEIGH
= 3,
RTNLGRP_TC
= 4,
RTNLGRP_IPV4_IFADDR
= 5,
};
Note that here, it is critical that the #define
s are mixed into the enum
definition, otherwise we'd get invalid code such as 3 = 3,
instead of the desired RTNLGRP_NEIGH = 3
.
Oh, and please don't use __RTNLGRP_MAX
as an identifier. Names containing two adjacent underscores or beginning with an underscore followed by an upper-case letter are reserved by the C standard. Using them in your own code leads to undefined behavior.
这篇关于迷惑MACRO和枚举定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!