繁体   English   中英

令人困惑的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 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)

#define做的这个枚举是什么。 RTNLGRP_NEIGH的值是多少 6 OR 3

谢谢

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_NEIGHmain会被替换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);
}

希望这不会造成混乱。

#define S混合到enum定义必须将没有效果enum的定义。 #define的位置无关紧要。 它们可以(可能应该)放置在定义之前或之后。

/* 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 ),因此他们希望为宏提供相同的值。 但是请注意,这种方法是有缺陷的,因为预处理器不会知道常量的值,因此如果RTNLGRP_NEIGH#define d为3 ,则您将无法执行#if RTNLGRP_NEIGH >= 3这样的事情。 因此,从本质上讲,他们的方法结合了使用宏(名称空间污染)和使用enum (在预处理时不可用)的缺点。

我以前也见过,也许更有用的模式是#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混合到enum定义中非常重要,否则我们将获得无效的代码(例如3 = 3,而不是所需的RTNLGRP_NEIGH = 3

哦,请不要使用__RTNLGRP_MAX作为标识符。 C标准保留包含两个相邻下划线或以下划线后跟大写字母开头的名称。 在您自己的代码中使用它们会导致未定义的行为。

RTNLGRP_NEIGH的值为3(这是第四个枚举常量: RTNLGRP_NONE的值为0, RTNLGRP_LINK的值为1, RTNLGRP_NOTIFY的值为2)。

#define有点奇怪-它很容易使人们想阻止您使用C预处理程序

这个想法是,它为您提供了可以测试的RTNLGRP_NEIGH宏,但是宏的扩展是枚举常数(拼写相同)。 扩展中没有无限循环,因为一旦宏被扩展,在重新扫描替换文本时就不会再次扩展。

因此,结果是您可以编写:

#ifdef RTNLGRP_NEIGH
   …code using RTNLGRP_NEIGH…
#endif

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM