C 如何理解;((尺寸)&;((类型*)0)>;成员)";?

C 如何理解;((尺寸)&;((类型*)0)>;成员)";?,c,kernel,C,Kernel,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 DNAM

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))
如何理解“((大小)和((类型*)0)->成员”?

谢谢

它返回指定结构成员的偏移量,将其从地址0开始计算。首先,它将地址0强制转换为正确的类型(即
(type*)
cast),然后将指定成员的偏移量添加到该基址。由于基址为0,因此可以有效地获得在宏中指定的成员的偏移量。

这是一种黑客攻击,它允许您在编译器不支持时模拟的功能:它利用了这样一个事实,即当基址设置为0时,
成员的地址等于其偏移量

考虑这个例子:

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

如果在地址
0xC000
分配
struct Test
,则
text
的地址将为
0xC000
,而
count
的地址将为
0xC020
。但是,如果基址为零(这是标准不允许的),则
text
的地址将为零,计数的地址将为
0x20
。将这些地址强制转换为
大小\u t
将提供相应成员的偏移量。

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

    1.                         0
    2.                ((TYPE *)0)
    3.              ( ((TYPE *)0)->MEMBER )
    4.             &( ((TYPE *)0)->MEMBER )
    5.  ( (size_t) &( ((TYPE *)0)->MEMBER )
  • 一切都以数字
    0
    开始
  • 0
    被强制转换为指向
    struct TYPE
    的指针。注意,我们让编译器相信在程序数据段的开头有这样一个
    struct
    (这通常是危险的,但我稍后会提到为什么不在这个特殊情况下)
  • 然后,引用该结构中的成员
    member
  • 未使用其内容,但使用其地址(带有
    &
  • 这个地址被转换回一个数字类型
    size\t
  • 由于结构的“开始”地址指定为
    0
    ,因此
    成员的地址(转换为数字时)是其在结构内的偏移量

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

    下面的表达:

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

    这也行。3264代表您选择的任意数字。添加了一个括号集以使其更清晰。

    这可能是重复的:此代码之所以安全,不是因为没有写入内存位置,而是因为没有访问内存位置。@这不是我的真名:这实际上取决于程序运行的特定计算机体系结构。然而,你是对的,因为这个问题涉及到Linux。我不清楚你认为什么取决于体系结构。不管怎样,如果从该指针读取,则会得到未定义的行为。计算是安全的,因为这纯粹是一个数学问题,没有任何东西试图实际读取问题中的内存。@这不是我的真名:是的,这正是我在原始答案中的观点。然而,我的回答是关于你的断言,代码是安全的,因为没有内存位置被访问过。这就是我所说的依赖于架构,这正是语言本身使行为“未定义”(而不是“错误”)的原因。在没有内存保护的OSs下,我使用这种技术来读(和写)以一致和可预测的方式直接连接到视频卡内存。在不同的操作系统/视频卡(“体系结构”)中,行为将完全不同。