用过Linux的程序员都知道,Linux提供了一个宏函数,可以根据成员变量的地址计算父对象的地址
宏函数的定义如下:
define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type )( (char )__mptr - offsetof(type,member) );})
今天偶然发现VxWorks6.9上也同样定义了一个类似功能的函数member_to_object,具体格式是(在jobQueueLib.h
中定义)
//jobQueueLib.h
define member_to_object(pMember, type, memberName) \
((type *)((char *)(pMember) - offsetof (type, memberName)))
member_to_object实现了container_of相同的功能,但格式上更简单,非常容易理解。
offsetof定义在stddef中,用来计算结构体成员变量的偏移值,具体格式是:
/* Offset of member MEMBER in a struct of type TYPE. */
define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
所以offsetof和member_to_object是一对逆运算,就像 * 和 &一样
在VxWorks6.9上测试的例子:
typedef struct memStruct
{
char a;
int b;
int c;
}MEMS;
MEMS m1;
void getoffset(void)
{
int *p;
m1.a=5;
m1.b=6;
m1.c=8;
printf("b offset is %d,c offset is %d\n",offsetof(MEMS,b),offsetof(MEMS,c));
p=&m1.c;
printf("member_to_object(pMember, type, memberName)\n");
printf("p=%p, member_to_object=%p \n ",p,member_to_object(p,MEMS,c));
printf("c addr=%p, m1 addr=%p \n ",&m1.c,&m1);
}
-> getoffset
b offset is 4,c offset is 8
member_to_object(pMember, type, memberName)
p=0x43636c, member_to_object=0x436364
c addr=0x43636c, m1 addr=0x436364
value = 36 = 0x24 = ‘$’
->