c - Measuring size of struct by counting size of members -
the code mentioned here gets list of network interfaces , corresponding addresses.
---------------------------------------------------------------- header file - ifaddrs.h ---------------------------------------------------------------- #ifndef generic_aix_ifaddrs_h #define generic_aix_ifaddrs_h #include <sys/socket.h> #include <net/if.h> #undef ifa_dstaddr #undef ifa_broadaddr #define ifa_broadaddr ifa_dstaddr struct ifaddrs { struct ifaddrs *ifa_next; char *ifa_name; unsigned int ifa_flags; struct sockaddr *ifa_addr; struct sockaddr *ifa_netmask; struct sockaddr *ifa_dstaddr; }; extern int getifaddrs(struct ifaddrs **); extern void freeifaddrs(struct ifaddrs *); #endif ---------------------------------------------------------------- source file - getifaddrs.c ---------------------------------------------------------------- #include <string.h> #include <sys/ioctl.h> #include "ifaddrs.h" /******************************************************************** *** note: generic version written aix 5.3 *** ********************************************************************/ #define max(x,y) ((x)>(y)?(x):(y)) #define size(p) max((p).sa_len,sizeof(p)) static struct sockaddr * sa_dup (struct sockaddr *sa1) { struct sockaddr *sa2; size_t sz = sa1->sa_len; sa2 = (struct sockaddr *) calloc(1,sz); memcpy(sa2,sa1,sz); return(sa2); } void freeifaddrs (struct ifaddrs *ifp) { if (null == ifp) return; free(ifp->ifa_name); free(ifp->ifa_addr); free(ifp->ifa_netmask); free(ifp->ifa_dstaddr); freeifaddrs(ifp->ifa_next); free(ifp); } int getifaddrs (struct ifaddrs **ifap) { int sd, ifsize; char *ccp, *ecp; struct ifconf ifc; struct ifreq *ifr; struct ifaddrs *cifa = null; /* current */ struct ifaddrs *pifa = null; /* previous */ const size_t ifreqsz = sizeof(struct ifreq); sd = socket(af_inet, sock_dgram, 0); *ifap = null; /* find how memory allocate siocgifconf call */ if (ioctl(sd, siocgsizifconf, (caddr_t)&ifsize) < 0) return(-1); ifc.ifc_req = (struct ifreq *) calloc(1,ifsize); ifc.ifc_len = ifsize; if (ioctl(sd, siocgifconf, &ifc) < 0) return(-1); ccp = (char *)ifc.ifc_req; ecp = ccp + ifsize; while (ccp < ecp) { ifr = (struct ifreq *) ccp; ifsize = sizeof(ifr->ifr_name) + size(ifr->ifr_addr); cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs)); cifa->ifa_next = null; cifa->ifa_name = strdup(ifr->ifr_name); if (pifa == null) *ifap = cifa; /* first 1 */ else pifa->ifa_next = cifa; if (ioctl(sd, siocgifaddr, ifr, ifreqsz) < 0) return(-1); cifa->ifa_addr = sa_dup(&ifr->ifr_addr); if (ioctl(sd, siocgifnetmask, ifr, ifreqsz) < 0) return(-1); cifa->ifa_netmask = sa_dup(&ifr->ifr_addr); cifa->ifa_flags = 0; cifa->ifa_dstaddr = null; if (0 == ioctl(sd, siocgifflags, ifr)) /* optional */ cifa->ifa_flags = ifr->ifr_flags; if (ioctl(sd, siocgifdstaddr, ifr, ifreqsz) < 0) { if (0 == ioctl(sd, siocgifbrdaddr, ifr, ifreqsz)) cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr); } else cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr); pifa = cifa; ccp += ifsize; } return 0; } i not understand reason line ifsize = sizeof(ifr->ifr_name) + size(ifr->ifr_addr); why directly using sizeof(struct ifreq) fails here?
edit 1: understand logic behind size macro.
**edit 2: struct ifreq as:
struct ifreq { #ifndef ifnamsiz /* in net_if.h */ #define ifnamsiz 16 #endif char ifr_name[ifnamsiz]; /* if name, e.g. "en0" */ union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; __ulong32_t ifru_flags; int ifru_metric; caddr_t ifru_data; u_short ifru_site6; __ulong32_t ifru_mtu; int ifru_baudrate; int ifru_checksum_offload[2]; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_metric ifr_ifru.ifru_metric /* metric */ #define ifr_data ifr_ifru.ifru_data /* use interface */ #define ifr_site6 ifr_ifru.ifru_site6 /* ipv6 site index */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu of interface */ #define ifr_isno ifr_ifru.ifru_data /* pointer if_netopts */ #define ifr_baudrate ifr_ifru.ifru_baudrate /* baudrate of interface */ #define ifr_checksum_offload ifr_ifru.ifru_checksum_offload[1] /* checksum offload active or not */ };
size(p) macro return maximum of ifr->ifr_addr.sa_len , sizeof(struct sockaddr).
size(ifr->ifr_addr) expanded max(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)).
max macro defined return greatest of these 2 , expanded like.
((ifr->ifr_addr.sa_len)>(sizeof(ifr->ifr_addr))?(ifr->ifr_addr.sa_len):(sizeof(ifr->ifr_addr)))
Comments
Post a Comment