linux-2.6.16 / include / linux / stddef.h中的代码是:
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname))
如何理解“((size_t)&((TYPE *)0) - > MEMBER)”?
谢谢
答案 0 :(得分:11)
操作顺序可以通过以下方式说明:
1. 0
2. ((TYPE *)0)
3. ( ((TYPE *)0)->MEMBER )
4. &( ((TYPE *)0)->MEMBER )
5. ( (size_t) &( ((TYPE *)0)->MEMBER )
0
开头。0
被转换为指向struct TYPE
的指针。 IOW,我们让编译器相信程序数据段的开头有这样一个struct
(这通常是危险的,但我稍后会提到为什么不在这种特殊情况下)。MEMBER
中的成员struct
。&
),size_t
。由于结构的“开始”的地址被指定为0
,MEMBER
的地址(转换为数字时)是结构中的偏移量。
这个特定代码无害的原因是没有写入任何内存位置,甚至没有访问过。一切都只涉及指向这些位置(但不包括其内容)和数字的指针。所有这些都保存在机器寄存器或通常的本地堆栈中。
以下表达式:
( (size_t) &( ((TYPE *)3264)->MEMBER ) - 3264 )
也会奏效。添加了括号集以使其更清晰。
答案 1 :(得分:3)
这是一个hack,它允许您在没有编译器支持的情况下模拟offsetof
的功能:它利用MEMBER
的地址等于其基址的基数的事实。设为零。
考虑这个例子:
struct Test {
char text[32];
int count;
}
如果struct Test
分配在0xC000
地址,则text
的地址为0xC000
,count
的地址为{{} 1}}。但是,如果基址为零(标准不允许),则0xC020
的地址将为零,并且计数的地址将为text
。将这些地址转换为0x20
会为您提供相应成员的偏移量。
答案 2 :(得分:0)
它返回指定结构成员的偏移量,使其偏离地址0.首先,它将地址0强制转换为正确的类型(即(TYPE*)
强制转换),然后添加偏移量指定的成员到该基地址。由于基址为0,因此您可以有效地获得在宏中指定的成员的偏移量。