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

Popular posts from this blog

ubuntu - PHP script to find files of certain extensions in a directory, returns populated array when run in browser, but empty array when run from terminal -

php - How can i create a user dashboard -

javascript - How to detect toggling of the fullscreen-toolbar in jQuery Mobile? -