[英]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_NEIGH
在main
會被替換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.