当前位置:  开发笔记 > 编程语言 > 正文

令人困惑的MACRO和枚举定义

如何解决《令人困惑的MACRO和枚举定义》经验,为你挑选了1个好方法。

我正在浏览一些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

谢谢



1> 5gon12eder..:

值为RTNLGRP_NEIGH3.您可以使用以下程序轻松测试.

#include 

/* 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自己的名称,因此RTNLGRP_NEIGHin main将替换为RTNLGRP_NEIGH.但由于扩展不是递归的,它将在此时停止,程序使用第四个enum常量RTNLGRP_NEIGH,因此值为3.

如果您不确定预处理器的作用,您始终可以使用-E开关进行编译并查看预处理的输出.编译上面的例子gcc -E给出(没有显示d40 #include标准库头的840行)

# 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混入enum定义的s对定义没有影响enum.#defines位于何处无关紧要.他们可以(也可能应该)在定义之前或之后放置.

/* 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)

他们编写这个weired代码的原因可能是他们想要使用重构旧代码

#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剐到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,

};

请注意,在这里,将#defines混合到enum定义中是至关重要的,否则我们会得到无效的代码,3 = 3,而不是所需的代码RTNLGRP_NEIGH = 3.

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

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有