有符号溢出未定义。无符号溢出定义为模算术。
所以我的问题是,以下是已定义还是未定义:
#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
,我的意思是任何+/-值。如果我理解正确的话,这应该可行。我对么?
指针运算是在抽象机中定义的。
在抽象机器中,ptr+x
仅在以下情况下有效ptr
存在于一个对象中,因此它的地址位于-x
的边缘。
这个抽象机器不关心指针或有符号或无符号整数的具体大小。在这个抽象机器中,有符号和无符号整数的值是实整数,或未指定的值。
minus1
与 32 位uintptr_t
等于0xffffffff,一个大的正整数。
Does element
一个对象内的点足够大,以至于 0xffffffff*sizeof(X) 之后它仍然在该对象内?不,不是的。
So element+minus1
是一个未定义的操作。任何事情都可能发生。
在您的硬件上,将指针算术简单地解释为机器代码may导致其缠绕。但依赖于此并不安全。
一方面,优化器有时喜欢证明事情。如果他们证明element
大于array
的地址,那么没有未签名的补充element
可以使其等于array
。所以编译器可以优化element+unsigned value == array
to false
.
如果您更改优化设置、升级编译器或完全无害的事情(例如更改内联位置或其他内联代码、链接时优化的启发式方法或月相变化),则可能会发生此类优化。
依赖它工作是危险的,即使它确实如此,因为你现在负责审计的不是源代码,而是它生成的机器代码。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)