指针在 C++ 中是否被视为无符号值?

Is a pointer considered an unsigned value in C++?

有符号溢出未定义。无符号溢出定义为模运算。

所以我的问题是,以下是已定义还是未定义:

#include <assert.h>
#include <cstdint>

struct X { int x;/* ... anything ... */ };

X array[3] = { 2, 3, 4 /* or other init values that is compatible with X */};
X* element = array + 1;

std::uintptr_t plus1 = 1;
std::uintptr_t minus1 = 0-plus1;


int main()
{
    printf("%p\n%p\n", element + plus1, array + 2);
    printf("\n");
    printf("%p\n%p\n", element + minus1, array);
    assert(element + plus1 == array + 2);
    assert(element + minus1 == array);
}

虽然我说 plus1/minus1,但我的意思是任何 +/- 值。如果我理解正确,这应该有效。我说得对吗?

  • std::uintptr_t 是无符号整数。
  • std::intptr_t 是有符号积分。

因此 std::uintptr_t 的溢出被定义,而 std::intptr_t 的溢出导致 UB。

此外,指针运算仅在数组内有效(到数组末尾的一位)。

minus1std::uintptr_t能容纳的最大数。

来自http://en.cppreference.com/w/cpp/language/operator_arithmetic

  • If the pointer P points to the ith element of an array, then the expressions P+n, n+P, and P-n are pointers of the same type that point to the i+nth, i+nth, and i-nth element of the same array, respectively. The result of pointer addition may also be a one-past-the-end pointer (that is, pointer P such that the expression P-1 points to the last element of the array). Any other situations (that is, attempts to generate a pointer that isn't pointing at an element of the same array or one past the end) invoke undefined behavior.

element + minus1element - 1 不同。
element + minus1超出数组有效范围,导致UB。

只有当所涉及的指针保留在单个数组对象内或刚好超过数组末尾时,指针算法才被明确定义。所以从技术上讲,表达式 element + minus1 是未定义的行为——因为 minus1 是一个非常大的值,它超出了数组的末尾。

现在在实践中,这可能会奏效,但在技术上仍未定义。

抽象机中定义了指针算法。

在抽象机中,ptr+x 仅当 ptr 存在于对象中且其地址在边的 -x 内时才有效。

这个抽象机不关心指针或有符号或无符号整数的具体大小。在此抽象机中,有符号和无符号整数的值是 实整数 或未指定的值。

minus1加上一个32位uintptr_t等于0xffffffff,一个大的正整数。

element 是否指向一个足够大的对象,以至于 0xffffffff*sizeof(X) 之后它仍然在该对象内?不,它没有。

所以element+minus1是一个未定义的操作。任何事情都可能发生。

在您的硬件上,将指针算术直接解释为机器代码可能导致它环绕。但是依赖这个并不安全。

一方面,优化器有时喜欢证明事情。如果他们证明 element 大于 array 的地址,那么 element 的无符号加法可能会使它等于 array.所以编译器可以优化 element+unsigned value == arrayfalse.

如果您更改优化设置、升级编译器或完全无害的事情(例如更改内联位置或其他内联代码)或 link 时间优化时的启发式方法,或月相变化。

依靠它工作是危险的,即使它确实如此,因为您现在负责审核的不是源代码,而是它生成的机器代码。