哪些指针值可以很好地计算?

cig*_*ien 4 c++ pointers language-lawyer

我的印象是,虽然取消引用不指向有效对象的指针是 UB,但简单地计算此类指针就可以了。

但是,如果我正确理解expr.add[4],则情况并非如此。

那么这些指针计算中哪些是明确定义的?

int a = 42;
int *p = &a;
p;           // valid, and obviously ok
p++;         // invalid, but ok, because one past the end of 'array' containing 1 element?
p++;         // UB ?
Run Code Online (Sandbox Code Playgroud)

这个案子怎么样?

int *p = nullptr;
p;                // invalid, and obviously ok (considered one past the end?)
p++;              // one past the end? or UB?
Run Code Online (Sandbox Code Playgroud)

gez*_*eza 5

在你的第一个例子中,第一个p++是明确定义的,因为非数组被认为是一个长度的数组。

这是相关报价(basic.compound/3.4):

出于指针算术 ([expr.add]) 和比较 ([expr.rel], [expr.eq]) 的目的,超过 n 个元素的数组 x 的最后一个元素末尾的指针被认为等价于指向 x 的假设数组元素 n 的指针和不是数组元素的类型 T对象被认为属于具有一个类型 T 的元素的数组

在 之后p++p它将指向(假设)数组的最后一个(也是唯一一个)元素,这是明确定义的。它不是“无效,但可以”,因为指向对象末尾的指针不是无效指针,basic.compound/3.2

指针类型的每个值都是以下之一:

  • [...]

  • 一个指针过去的对象的端

  • [...]

  • 无效的指针值。

p++一个示例中的第二个是 UB,因为结果将指向未定义的假设 (&a)[1] 元素之后。

在您的第二个示例中,p++是 UB,因为只能将 0 添加到nullptr( expr.add/4.1 ):

  • 如果 P 计算为空指针值而 J 计算为 0,则结果为空指针值。

  • [...]

  • 否则,行为是 undefined