是否对 C++ 中定义的空指针进行成员访问?

Is member access on a null pointer defined in C++?

地址计算是否基于 C++ 中的空指针定义行为?这是一个简单的示例程序。

struct A { int x; };
int main() {
  A* p = nullptr;
  &(p->x);  // is this undefined behavior?
  return 0;
}

谢谢。

编辑 下标包含在 .

&(p->x);  // is this undefined behavior?

标准对此有点模糊:

[expr.ref] ... The expression E1->E2 is converted to the equivalent form (*(E1)).E2;

[expr.unary.op] The unary * operator ... the result is an lvalue referring to the object ... to which the expression points.

该部分没有明确提及 UB。引用的规则似乎与空指针不指向任何对象这一事实相冲突。这可以解释为是的,行为未定义。

[expr.unary.op] The result of the unary & operator is a pointer to its operand. ... if the operand is an lvalue of type T, the resulting expression is a prvalue of type “pointer to T” whose result is a pointer to the designated object ([intro.memory]).

同样,不存在指定的对象。请注意,操作数左值绝不会转换为右值,这肯定是 UB。

早在 2000 年就有 CWG issue 阐明通过 null 的间接寻址是否未定义。提议的决议 (2004) 阐明通过 null 的间接寻址是 not UB,似乎 not 到目前为止已添加到标准中。

然而,它是否是 UB 并不重要,因为您不需要这样做。至少,结果指针将是无效的,因此无用。

如果您打算将指针转换为整数以获取成员的偏移量,则无需执行此操作,因为您可以使用标准库中的 offsetof 宏,它不会没有UB。


&(p[1]); // undefined?

在这里,行为很明显是未定义的:

[expr.sub] ... The expression E1[E2] is identical (by definition) to *((E1)+(E2)), except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.

[expr.add] When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.

  • If P evaluates to a null pointer value and J evaluates to 0 (does not apply)

  • Otherwise, if P points to an array element (does not apply)

  • Otherwise, the behavior is undefined.


&(p[0]); // undefined?

根据之前的规则,第一个选项适用:

If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

现在我们又回到了通过这个 null 间接寻址是否是 UB 的问题。见答案开头。

不过,这并不重要。没有必要写这个,因为这是写 sizeof(int) * i 的简单不必要的复杂方式(i 分别为 1 和 0)。