5

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)”?
谢谢

4

3 回答 3

13

操作顺序可以用以下方式说明:

    1.                         0
    2.                ((TYPE *)0)
    3.              ( ((TYPE *)0)->MEMBER )
    4.             &( ((TYPE *)0)->MEMBER )
    5.  ( (size_t) &( ((TYPE *)0)->MEMBER )
  1. 一切都以数字开头0
  2. 0被强制转换为指向 的指针struct TYPE。IOW,我们让编译器相信struct在程序数据段的开头有这样一个(这通常很危险,但我稍后会提到为什么在这种特殊情况下不这样做)。
  3. 然后,引用MEMBER其中的成员struct
  4. 它的内容没有被使用,但它的地址被占用(用&),
  5. 并将这个地址转换回数字类型size_t

由于结构的“开始”地址指定为0,因此MEMBER(转换为数字时)的地址是其在结构中的偏移量。

这个特定代码无害的原因是没有写入内存位置,甚至没有访问过。一切都只涉及指向这些位置(但不包括它们的内容)和数字的指针。它们都保存在机器寄存器或通常的本地堆栈中。

以下表达式:

      ( (size_t) &( ((TYPE *)3264)->MEMBER ) - 3264 )

也可以。3264 代表您选择的任何数字。添加了括号集以使其更清晰。

于 2013-09-01T02:51:17.307 回答
3

这是一种技巧,可让您模拟编译器不支持时的功能:它利用了当基地址设置为零时地址等于其偏移量offsetof的事实。MEMBER

考虑这个例子:

struct Test {
    char text[32];
    int count;
}

如果struct Test在地址分配0xC000,则地址为text0xC000地址count0xC020。但是,如果基地址为零(标准不允许),则 的地址text将为 0,而计数的地址为0x20。将这些地址转换为size_t给您相应成员的偏移量。

于 2013-09-01T02:50:17.163 回答
0

它通过基于地址 0 来返回指定结构成员的偏移量。首先它将地址 0 转换为正确的类型(即转换(TYPE*)),然后将指定成员的偏移量添加到该基地址。由于基地址为 0,因此您有效地获得了您在宏中指定的成员的偏移量。

于 2013-09-01T02:49:34.787 回答