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 #defined 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 #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 less confusing.
the #defines mixed enum definition have no effect enum definition. doesn't matter #defines 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 #defined 3 literally. so, in essence, approach combines disadvantages of using macros (name-space pollution) of using enums (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 #defines 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