簡體   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