一元 & 运算符能否产生地址 0(空指针)?
Can the unary & operator yield the address 0 (null pointer)?
C2x,6.5.3.2 地址和间接运算符,语义,3:
The unary & operator yields the address of its operand.
一个简单的问题:一元运算符 &
可以产生地址 0
(空指针)吗?
有什么例子/经验吗?
标准的相关部分是 6.3.2.3/3 (N2731),其中规定
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
因此,&
作用于任何对象的结果保证与空指针“比较不相等”。
可以。但是你必须竭尽全力让它成为可能。
有两种方法可以对实际对象执行此操作:
构造一个目标文件或链接器符号文件,您要链接的对象文件或链接器符号文件在 NULL 处导出符号。如果你 & 在那你会得到 NULL。
在某些平台上是 libc。您定义的第一个符号是 NULL。至少在一个平台上,堆管理器不得不应对这一点,因此对其进行了仔细的编码,这样编译器就永远不会观察到堆 HEAD 指针存储在 NULL 的事实。
请注意,这两个 waaaay 都来自可移植的 C,这就是重点。如果你得到 &
到 return NULL,你就会知道你做到了。这不是偶然发生的。
但是还有另一种方法:我们可以构造一个不包含真实对象的表达式,其中 &
return 是 0。像这样:
&(((struct some_struct *)0)->first_member)
只见于
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
不要这样做。 #include <stddef>
并让编译器定义 offsetof
。此实现中存在错误。
C 2018 6.5.3.2 1 说:
The operand of the unary &
operator shall be either a function designator, the result of a []
or unary *
operator, or an lvalue that designates an object that is not a bit-field…
如果操作数是函数指示符,则它不能是空指针,因为 C 2018 6.3.2.3 3 说空指针“保证与指向任何对象或函数的指针比较不相等”,但是函数作为空指针的指示符将与另一个(可能不同的)空指针比较,因为 C 2018 6.5.9 6 表示两个空指针比较相等。
如果它是指定对象的左值,那么它不能是空指针,同理。 (注意6.5.3.2 1特指指定对象的左值,一般来说,左值是可能指定对象的表达式,即必须有对象类型.但是6.5.3.2 1中的约束明确告诉我们操作数必须实际指定一个对象。)
剩下 []
或一元 *
的结果。前者是根据后者来定义的,所以我们只需要考虑一元*
。 C 2018 6.5.3.2 2 说“一元 *
运算符的操作数应具有指针类型”,但并不要求它指向实际对象或函数或 non-null。 6.5.3.2 4 表示“……如果操作数指向一个函数,则结果是一个函数指示符;如果它指向一个对象,则结果是指定该对象的左值……”但没有明确说明如果操作数是空指针,结果是什么。它继续说“如果为指针分配了无效值,则一元 *
运算符的行为未定义。”那里的文本引用了注释 106,它说“......在一元 *
运算符取消引用指针的无效值中,有一个空指针,一个与指向的对象类型不恰当对齐的地址,以及生命周期结束后的对象。”
因此,C 标准没有定义一元 &
会产生空指针的行为。当然,它可能通过标准未定义的行为发生。
C2x,6.5.3.2 地址和间接运算符,语义,3:
The unary & operator yields the address of its operand.
一个简单的问题:一元运算符 &
可以产生地址 0
(空指针)吗?
有什么例子/经验吗?
标准的相关部分是 6.3.2.3/3 (N2731),其中规定
If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
因此,&
作用于任何对象的结果保证与空指针“比较不相等”。
可以。但是你必须竭尽全力让它成为可能。
有两种方法可以对实际对象执行此操作:
构造一个目标文件或链接器符号文件,您要链接的对象文件或链接器符号文件在 NULL 处导出符号。如果你 & 在那你会得到 NULL。
在某些平台上是 libc。您定义的第一个符号是 NULL。至少在一个平台上,堆管理器不得不应对这一点,因此对其进行了仔细的编码,这样编译器就永远不会观察到堆 HEAD 指针存储在 NULL 的事实。
请注意,这两个 waaaay 都来自可移植的 C,这就是重点。如果你得到 &
到 return NULL,你就会知道你做到了。这不是偶然发生的。
但是还有另一种方法:我们可以构造一个不包含真实对象的表达式,其中 &
return 是 0。像这样:
&(((struct some_struct *)0)->first_member)
只见于
#define offsetof(type, member) ((size_t)&(((type *)0)->member))
不要这样做。 #include <stddef>
并让编译器定义 offsetof
。此实现中存在错误。
C 2018 6.5.3.2 1 说:
The operand of the unary
&
operator shall be either a function designator, the result of a[]
or unary*
operator, or an lvalue that designates an object that is not a bit-field…
如果操作数是函数指示符,则它不能是空指针,因为 C 2018 6.3.2.3 3 说空指针“保证与指向任何对象或函数的指针比较不相等”,但是函数作为空指针的指示符将与另一个(可能不同的)空指针比较,因为 C 2018 6.5.9 6 表示两个空指针比较相等。
如果它是指定对象的左值,那么它不能是空指针,同理。 (注意6.5.3.2 1特指指定对象的左值,一般来说,左值是可能指定对象的表达式,即必须有对象类型.但是6.5.3.2 1中的约束明确告诉我们操作数必须实际指定一个对象。)
剩下 []
或一元 *
的结果。前者是根据后者来定义的,所以我们只需要考虑一元*
。 C 2018 6.5.3.2 2 说“一元 *
运算符的操作数应具有指针类型”,但并不要求它指向实际对象或函数或 non-null。 6.5.3.2 4 表示“……如果操作数指向一个函数,则结果是一个函数指示符;如果它指向一个对象,则结果是指定该对象的左值……”但没有明确说明如果操作数是空指针,结果是什么。它继续说“如果为指针分配了无效值,则一元 *
运算符的行为未定义。”那里的文本引用了注释 106,它说“......在一元 *
运算符取消引用指针的无效值中,有一个空指针,一个与指向的对象类型不恰当对齐的地址,以及生命周期结束后的对象。”
因此,C 标准没有定义一元 &
会产生空指针的行为。当然,它可能通过标准未定义的行为发生。