6

我有这段代码。它似乎在这里取消引用空指针,但随后将结果与unsigned int. 我真的不明白整个部分。它的目的是什么?这是指针算术的一种形式吗?

struct hi  
{
   long a;  
   int b;  
   long c;  
};  

int main()  
{  
    struct hi ob={3,4,5};  
    struct hi *ptr=&ob;  
    int num= (unsigned int) & (((struct hi *)0)->b);  

   printf("%d",num);  
   printf("%d",*(int *)((char *)ptr + (unsigned int) & (((struct hi *)0)->b)));  
}  

我得到的输出是 44。但它是如何工作的?

4

5 回答 5

8

它并没有真正取消引用空指针。您应该查看整个代码。代码说的是:取 number 0,将其视为,在它指向的结构中struct hi *选择元素,并获取该元素的地址。b此操作的结果将是元素b相对于结构开头的偏移量。当您将其添加到指针时,您将获得b等于4.

于 2010-12-26T04:53:24.853 回答
7

这为您提供了结构b内字段的字节偏移量hi

((struct hi *)0)是一个指向结构的指针hi,从 address 开始0

(((struct hi *)0)->b)b上述结构的字段

& (((struct hi *)0)->b)是上述字段的地址。因为hi结构位于 address 0,所以这是结构内的偏移量b

(unsigned int) & (((struct hi *)0)->b)是从地址类型到 的转换unsigned int,因此它可以用作数字。

您实际上并没有取消引用NULL指针。你只是在做指针算术。


访问(((struct hi *)0)->b)会给你一个分段错误,因为你试图访问一个禁止的内存位置。

使用& (((struct hi *)0)->b)不会给您带来分段错误,因为您只是获取该禁止内存位置的地址,但您并没有尝试访问该位置。

于 2010-12-26T04:52:45.970 回答
3

您必须使用 32 位编译器(或 Windows 上的 64 位编译器)。

第一个表达式 - for num- 是offsetof宏 from的常见实现<stddef.h>;它不是便携式的,但它通常可以工作。

第二个表达式将其添加到 0(空指针)并给出相同的答案 - 4。 第二个表达式将 4 添加到ptr指向对象的基地址,即结构中的值 4。

您的输出不包含换行符 - 它可能应该(该行为不是完全可移植的,因为如果您不包含换行符,它是实现定义的:C99 §7.19.2:“最后一行是否需要终止换行符是实现定义的。”)。在 Unix 机器上,它是混乱的,因为下一个提示将立即出现在 44 之后。

于 2010-12-26T04:54:06.853 回答
3

这不是“和”,这是取右侧参数的地址。
这是在运行时获取结构成员偏移量的标准技巧。您将 0 转换为指向 struct hi 的指针,然后引用“b”成员并获取其地址。然后将此偏移量添加到指针“ptr”并获得由ptr指向的结构的“b”字段的真实地址,即ob。然后将该指针转换回 int 指针(因为 b 是 int)并输出它。这是第 2 次印刷。第一次打印输出num,它是4不是因为b的值是4,而是因为4是hi struct中b字段的偏移量。哪个是 sizeof(int),因为 b 跟在 a 之后,而 a 是 int ......希望这是有道理的 :)

于 2010-12-26T04:56:47.417 回答
0

只是为了澄清您必须了解 NULL 指针取消引用与何时不被视为取消引用之间的区别。规范实际上规定不会发生取消引用,并且当您在表达式中使用 & (地址)运算符时,实际上已被优化掉。

所以 &((struct T*)0)->b) 实际上优化了 -> 并且只是从偏移量 0 跳转了那个字节数并假设它是一个 struct T *。这确实使新手感到困惑。然而,它在 Linux 内核中被广泛使用——并且提供了一个真正意义上的 list_entry、list_head 和各种新手无法理解的指针算术魔法。

无论如何,这是一种在 struct T 对象中查找“b”偏移量的编程方式。它用于 offsetof 以及其他 list_head 操作,例如 list_entry。

有关更多信息 - 您可以在 Robert Love 的名为“Linux Kernel Development”的书中阅读相关内容。

于 2011-01-01T21:51:46.303 回答