1 /* 2 * create a Link Level name for this device 3 */ 4 unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf)); 5 namelen = strlen(ifp->if_name); 6 unitlen = strlen(unitname); 7 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 8 masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + 9 unitlen + namelen; 10 socksize = masklen + ifp->if_addrlen; 11 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 12 socksize = ROUNDUP(socksize); 13 if (socksize < sizeof(*sdl)) 14 socksize = sizeof(*sdl); 15 ifasize = sizeof(*ifa) + 2 * socksize;
图3-35 if_attach函数:计算链路层地址大小
个人c没怎么学,感觉很吃力。
第一个问题是sprint_d函数是什么?找到源代码是
static char *
sprint_d(n, buf, buflen)
u_int n;
char *buf;
int buflen;
{
register char *cp = buf + buflen - 1;
*cp = 0;
do {
cp--;
*cp = "0123456789"[n % 10]; //不错的代码。呵呵
n /= 10;
} while (n != 0);
return (cp);
}
其实,sprint_d就是把u_int类型的数转化为字符串。
第二个问题是,这个第七行的宏函数是神马东西?
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
1. caddr_t是核心地址,一般被定义为char*;
2. &((t *)0)->m)这是神马,其实&在这是取地址符,(t *)0是对编译器说:“我这是t结构的指针,地址是0”,所以我们获得的t指针的首地址是0(或者说基址是0)。所以,&((t *)0)->m)就是m在结构t中的偏移量了。
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
这个就是把a上舍入为一个长整数。sizeof(long)一般为4(有的时候是8),所以(sizeof(long) - 1)的二进制码为11,所以前面的((a) - 1)不管是什么,
(((a) - 1) | (sizeof(long) - 1))最后的结果的最低的2位的二进制码都是11。再加上1所以ROUNDUP(a)的结果是把a的第二位变成00且往第三位进1。产生的结果是ROUNDUP(a)永远是4的倍数,例如1--4,2--4,3--4,5---8,6---8,11---12,15--16,等等、、、