的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到自己的名稱,在該main
RTNLGRP_NEIGH
將由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)
他們之所以寫這篇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
d到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
s的混合到enum
定義,否則我們會得到無效的代碼,如3 = 3,
,而不是期望RTNLGRP_NEIGH = 3
。
哦,請不要使用__RTNLGRP_MAX
作爲標識符。包含兩個相鄰下劃線或以下劃線開頭且後跟大寫字母的名稱由C標準保留。在你自己的代碼中使用它們會導致未定義的行爲。
原作者應該比混合#define和enum更像混亂,看起來像一團糟 –