哪些指针值被明确定义为可以计算?

What pointer values are well-defined to compute?

我的印象是,虽然取消引用未指向有效对象的指针是 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 ?

这个案例怎么样?

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

在您的第一个示例中,第一个 p++ 是明确定义的,因为非数组被视为单长度数组。

这是相关的引用 (basic.compound/3.4):

For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), a pointer past the end of the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical array element n of x and an object of type T that is not an array element is considered to belong to an array with one element of type T.

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

Every value of pointer type is one of the following:

  • [...]

  • a pointer past the end of an object

  • [...]

  • an invalid pointer value.

第一个例子的第二个p++是UB,因为结果会指向假设的(&a)[1]元素之后,这个元素没有定义。

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

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

  • [...]

  • Otherwise, the behavior is undefined.