迷惑MACRO和枚举定义 [英] Confusing MACRO and enum definition

查看:237
本文介绍了迷惑MACRO和枚举定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在浏览一些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 #defined 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 #included 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 #defines mixed into the enum definition have no effect to the enum definition. It doesn't matter where the #defines 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 #defined to 3 literally. So, in essence, their approach combines the disadvantages of using macros (name-space pollution) with those of using enums (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 #defines 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆