通过计算成员的大小来测量结构的大小

时间:2013-08-01 06:20:40

标签: c networking struct aix

提到的代码here获取网络接口和相应地址的列表。

----------------------------------------------------------------
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: this generic version written specifically for 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 much memory to allocate for the 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 one */
    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;
}

我不明白行ifsize = sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr);的原因为何直接使用sizeof(struct ifreq)会失败?

编辑1:此外,我想了解SIZE宏背后的逻辑。

**编辑2:struct ifreq如下:

struct  ifreq {
#ifndef IFNAMSIZ        /* Also 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      /* for use by 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 to 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 */
};

2 个答案:

答案 0 :(得分:0)

SIZE(p)宏将返回ifr->ifr_addr.sa_lensizeof(struct sockaddr)的最大值。

SIZE(ifr->ifr_addr)将扩展为MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr))

定义MAX宏以返回这两者中的最大值,并将像。

一样进行扩展

((ifr->ifr_addr.sa_len)>(sizeof(ifr->ifr_addr))?(ifr->ifr_addr.sa_len):(sizeof(ifr->ifr_addr)))

答案 1 :(得分:0)

了解Struct padding and alignment。你会得到答案。