“(s*)0”在“(size_t)&(((s*)0)->m)”中的含义是什么?(涉及IT技术)

4
这是在stddef.h中的一系列宏之一。
#define offsetof(s,m)   (size_t)&(((s *)0)->m)

What does (s *)0 mean?


http://en.wikipedia.org/wiki/Offsetof - billz
应该注意的是,这种行为是未定义的,您不应在程序中使用这种东西。一些编译器使用内置函数来实现 offsetof。 - R. Martinho Fernandes
仅澄清一下:offsetof(type,member) 的行为由 C++ 标准(C++11 18.2/4)定义,但仅当 type 是一个标准布局类型且 member 引用非静态数据成员时。这个特定的 offsetof 实现依赖于不被标准定义而是由具体的 C++ 实现定义的行为。换句话说,在您的代码中使用 offsetof 是完全可以的,但像这个 offsetof 实现所做的那样在您的代码中解引用空指针是不可移植的。 - Casey
6个回答

7

这是一种写法来表示一个类型为指向s的指针NULL指针。通过获取一个地址为0的s成员m的地址,可以得到在s内的m偏移量。


顺便问一下,((s *)0)->m 不会引发未定义行为吗? - Nawaz
1
@Nawaz:但是这有一个非常明确定义的行为:它会给你“对象”m,它是结构体s的成员,驻留在内存位置0。未定义的行为将是对m或s的任何读取或写入访问。(在该未定义情况下最可能的行为是内存访问违规,这将立即导致程序崩溃 - 除非操作系统不禁止对该内存地址范围的任何访问。) - comonad
@comonad:我是从语言角度来说的,而不是编译器对你的代码做了什么。我相信这种语言是不允许的! - Nawaz
@Nawaz -- 请注意,这个例子来自于 stddef.h。我知道这并不能证明什么,但它表明了这种技术是多么被接受。我非常确定这是合法的,因为正如 @comonad 所说,我们所做的只是计算地址:我们并不会用它做任何事情。 - Ernest Friedman-Hill
@Nawaz:我非常确定C++允许这样做;我猜Java不行。在C++中,只有当m在s的虚表中时才会出现问题。(例如虚函数或者s的虚拟超类中的任何内容。)如果你是对的,那么在嵌入式系统中怎么办?这些系统没有内存限制,甚至没有实际的内存结构位于地址0,就像在DOS中一样。 - comonad
@comonad:Java?你怎么能在这里谈论Java!无论如何,在C++中,许多程序员所钟爱的东西实际上是未定义行为(UB)!如果某些东西(UB)在所有编译器上都可以工作,那也并不重要。它仍然是UB。 - Nawaz

3

这是一种类型转换,将0转换为s的指针


需要注意的是,应该使用 static_cast 或其中一个 C++ 强制转换。 - Shoe
1
@Jeffrey stddef.h 用于 C 和 C++,因此它不使用 C++ 特定的功能。 - Barmar

0
这是将指针转换为s。在这种情况下,s是宏的一个参数,希望是类型名称。

希望是一个结构体类型名称。 - Barmar

0
创建一个类型为s的指针,并将其值设置为零(null)。

0

s在这里应该是一个类型名,比如int,因此(s*)0基本上是将0强制转换为指针类型。


0

0 不仅是整数零,还是空指针。因此,((S*)0) 将空指针转换为指向 s 的指针(其中 s 可能是一个结构体)。


1
在这种情况下,它是0更重要。它不被用作空指针。 - Barmar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接