【问题标题】:Is member access on a null pointer defined in C++?是否在 C++ 中定义了对空指针的成员访问?
【发布时间】:2020-10-01 18:44:05
【问题描述】:

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

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

谢谢。

EDITthis other question 中涵盖了下标。

【问题讨论】:

  • 在我看来像 UB。 (对于第一个例子,你的意思是 ` &(p->x);` 吗?)
  • @cigien 感谢您的指点(不是双关语)。这回答了第二个问题,但不是关于成员访问的第一个问题。
  • 肯定是UB,p指向的地方没有对象,所以即使在你取地址之前,做p->x(*p).x一样,也就是UB。
  • 您在这里提出了两个不同的问题。成员访问和下标不一样。其中一个问题比另一个问题更微妙。
  • 这能回答你的问题吗:stackoverflow.com/questions/2474018/…

标签: c++ language-lawyer dereference null-pointer


【解决方案1】:
&(p->x);  // is this undefined behavior?

标准对此有点模糊:

[expr.ref] ... 表达式 E1->E2 被转换为等价形式 (*(E1)).E2;

[expr.unary.op] 一元 * 运算符...结果是一个左值,引用表达式指向的对象...。

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

[expr.unary.op] 一元 & 运算符的结果是指向其操作数的指针。 ...如果操作数是 T 类型的左值,则结果表达式是“指向 T”的指针类型的纯右值,其结果是指向指定对象 ([intro.memory]) 的指针。

同样,不存在指定对象。请注意,操作数左值在任何时候都不会转换为右值,而右值肯定是 UB。

早在 2000 年,CWG issue 就澄清了通过 null 进行的间接是否未定义。提议的决议(2004 年)将澄清通过 null 的间接性是 not UB,目前看来 not 已添加到标准中。

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

如果您打算将指针转换为整数以获取成员的偏移量,则无需这样做,因为您可以使用标准库中的 offsetof 宏,它没有 UB .


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

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

[expr.sub] ... 表达式 E1[E2] 与 *((E1)+(E2)) 相同(根据定义),除了在数组操作数的情况下,结果是左值如果该操作数是左值,否则为 xvalue。

[expr.add] 当一个整数类型的表达式J被一个指针类型的表达式P添加或减去时,结果的类型为P。

  • 如果 P 计算结果为空指针值且 J 计算结果为 0(不适用)

  • 否则,如果P指向一个数组元素(不适用)

  • 否则,行为未定义。


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

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

如果 P 求值为空指针值,J 求值为 0,则结​​果为空指针值。

现在我们回到通过这个 null 的间接性是否是 UB 的问题。请参阅答案的开头。

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

【讨论】:

  • "这可以解释为是的,行为未定义。" ——我没有看到任何其他可能的解释。这样的解释必须解释表达式指向哪个对象
  • @M.M 很公平。我删除了。
猜你喜欢
  • 2020-06-24
  • 1970-01-01
  • 2016-05-24
  • 2015-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-16
相关资源
最近更新 更多