签名溢出未定义。无符号溢出被定义为模块化算法。
因此,我的问题是,下列定义或未定义:
#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,但实际上我的意思是任何+/-值。如果我正确理解它,这应该是可行的。我说的对吗?
发布于 2018-01-24 18:29:27
在抽象机器中定义指针算法。
在抽象机器中,只有当ptr+x存在于对象中,使其地址位于边缘的-x中时,ptr才是有效的。
此抽象机器不关心指针或有符号整数或无符号整数的特定大小。在此抽象机器中,有符号整数和无符号整数的值为实整数或未指定的值。
具有32位minus1的uintptr_t等于0 0xffffffff,这是一个大的正整数。
element是否指向一个大到足以使0 0xffffffff*sizeof(X)稍后仍在对象内的对象内?不,不需要。
因此,element+minus1是一个未定义的操作。任何事都有可能发生。
在您的硬件上,将指针算法简单地插入到机器代码中可能会导致它被包围。但依靠这个并不安全。
首先,优化者有时喜欢证明事实。如果它们证明element大于array的地址,那么任何对element的无符号加法都不可能使其与array相等,因此编译器可以将element+unsigned value == array优化为false。
如果您更改优化设置、升级编译器或完全无害的事情(如内联的更改)、内联的其他代码、链接时间优化时的启发式或月亮的变化阶段,就会发生这样的优化。
依赖于它的工作是危险的,即使是这样,因为您现在开始负责审计它生成的机器代码,而不是源代码。
发布于 2018-01-24 18:19:41
指针算法只有在所涉及的指针保持在单个数组对象内或仅在数组结束后才能很好地定义。所以从技术上讲,表达式element + minus1是未定义的行为--因为minus1是一个非常大的值,它运行在数组的末尾。
现在,在实践中,这可能是可行的,但在技术上仍未定义。
发布于 2018-01-24 18:16:15
std::uintptr_t是一个无符号积分。std::intptr_t是一个有符号的积分。因此定义了std::uintptr_t溢出,而std::intptr_t溢出导致UB。
此外,指针算法仅在数组中有效(指向数组结束后的一个数组)。
minus1是std::uintptr_t能容纳的最大数字。
来自arithmetic
element + minus1与element - 1不一样。
element + minus1在数组的有效范围之外,因此导致UB。
https://stackoverflow.com/questions/48429021
复制相似问题