我一直在寻找很长很难的链接(最后的链接),以解释对MACRO的偏移的实现:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
特别是,取消引用NULL以获取结构中成员的偏移量。许多文章通过说NULL指针实际上从未真正解除引用来掩盖原因,但这对我来说没有意义。
以下是我尝试理解的一些链接:
我正在寻找和尝试理解的是一步一步,打破了对编译器如何解释MACRO定义的理解,这最终将解释NULL指针实际上是如何被解除引用的。
编辑: 即使其他问题回答了我的问题,但正如原帖中指出的那样,它们对我有意义。 @dasblinkenlight的答案揭示了我对其他问题的问题,即我们实际上并没有解除引用指针的问题。
答案 0 :(得分:4)
特别是,取消引用NULL以获取结构中成员的偏移量。
指针没有解除引用,因为运算符->
撤消了运算符&
的效果:
NULL
:((TYPE *)0)->MEMBER
&
使其成为地址计算:&((TYPE *)0)->MEMBER
许多文章通过说NULL指针实际上从未被真正解除引用来掩盖原因,但这对我来说没有意义。
以此示例为例:
int a;
int *p = &a;
int b = *p; // <<== This is a dereference
int *q = &(*p); // <<== This is not a dereference
两个运算符*
和&
会消除彼此的影响。运算符->
是一种&#34;语法糖&#34;在*
和.
之上,&
也可以撤消其效果。
当编译器看到表达式somePointer->a
时,它会获取指针somePointer
的数值,添加成员a
的偏移量,并学习内存中可以操作的位置。你可以对记忆中的一个地方做三件事:
第1项和第2项(读写)构成解除引用。但是,第3项没有解除引用,因为不访问特定地址的内存。
宏基本上要求编译器计算成员a
的地址,假设基址为零。返回的a
地址自然等于a
的偏移量。您需要做的就是获取其地址,这是您对操作员&
所做的。