在 C 中计算指向未初始化内存未定义行为的指针?

Is computing a pointer to uninitialized memory undefined behavior in C?

如果我没理解错的话,这个程序在 C++ 中有未定义的行为,因为中间值 p + 1 是指向未初始化内存的指针:

int main () {
    int x = 0;
    int *p = &x;
    p = p + 1 - 1;
    *p = 5;
}

如果 void 被放入 main 的参数列表中(根据 C 语法的要求),它是否也是 C 中的未定义行为?

没有未定义的行为。您可以将单个对象视为具有一个元素的数组。使用指针算法,指针可能指向数组最后一个元素之后的元素,所以这个语句

p = p + 1 - 1;

正确。

来自 C 标准(6.5.6 加法运算符)

7 For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

  1. ...Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object.

注意那个

  1. ...If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

我认为 OP 选择 p + 1 - 1 作为示例有点不幸,因为 p + 1 不是 中所示的未定义行为。

如果我们考虑p + 2 - 2,这个问题会更有趣。这里 p + 2 确实是未定义的行为。但是,如果在完整的表达式中我们“撤销此计算”,这有关系吗?

整数有一个模拟。例如。给定 i 一个有符号整数,如果 i + 2 溢出,因此是未定义的行为,表达式 i + 2 - 2 是正确的还是未定义的行为?

两者的答案都是未定义的行为。如果一个表达式是未定义的行为并且程序将在其评估中到达该表达式,那么整个程序将表现出未定义的行为。

关于此有一个更广为人知的案例:计算有符号整数的中点:如果 a + b 溢出,(a + b) / 2 是 UB,即使最终值适合数据类型。