c - Confusing MACRO and enum definition -
i browsing route netlink source code.
i wanted figure out 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 enum #define doing. value of rtnlgrp_neigh? 6 or 3
thanks
the value of rtnlgrp_neigh
3. can test 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 #define
d own name, rtnlgrp_neigh
in main
replaced rtnlgrp_neigh
. since expansion not recursive, stop @ point , program use enum
constant rtnlgrp_neigh
fourth , therefore has value 3.
if not sure preprocessor does, can compile -e
switch , @ pre-processed output. compiling above example gcc -e
gives (not showing 840 lines of #include
d 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 less confusing.
the #define
s mixed enum
definition have no effect enum
definition. doesn't matter #define
s located. (and should) have been placed before or after 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 wrote weired code wanted 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 enum
instead. because existing code might rely on fact identifiers macros (such testing #ifdef rtnlgrp_neigh
) wanted provide macros same value. note approach flawed, however, because preprocessor won't know value of constant cannot things #if rtnlgrp_neigh >= 3
could, had rtnlgrp_neigh
been #define
d 3
literally. so, in essence, approach combines disadvantages of using macros (name-space pollution) of using enum
s (not available @ pre-processing time).
a maybe more useful pattern have seen before #define
constants 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 pre-processed following.
enum rtnetlink_groups { rtnlgrp_none = 0, rtnlgrp_link = 1, rtnlgrp_notify = 2, rtnlgrp_neigh = 3, rtnlgrp_tc = 4, rtnlgrp_ipv4_ifaddr = 5, };
note here, critical #define
s mixed enum
definition, otherwise we'd invalid code such 3 = 3,
instead of desired rtnlgrp_neigh = 3
.
oh, , please don't use __rtnlgrp_max
identifier. names containing 2 adjacent underscores or beginning underscore followed upper-case letter reserved c standard. using them in own code leads undefined behavior.
Comments
Post a Comment