下面的示例在调用look_back_1()或look_back_2()时应该崩溃。 原因:当对无符号变量求反时,结果应保持无符号。
#include <stdio.h>
int look_back_1(int *arr, unsigned int nmElems, unsigned long dist)
{
int *elem = arr + nmElems;
elem += -dist;
return (*elem);
}
int look_back_2(int *arr, unsigned int nmElems, unsigned int dist)
{
int *elem = arr + nmElems;
elem += -dist;
return (*elem);
}
int main(int argc, char **argv)
{
int arr[100] = { 0, };
printf("1. %d\n", look_back_1(arr, 100, 1)); // <NEEDS TO CRASH, BUT WORKS????>>
printf("2. %d\n", look_back_2(arr, 100, 1)); // <<CRASH!!!!!>>
}
当进行数组越界访问时,GCC 4.5 在每个函数调用中都会崩溃。 编译器针对这两种情况发出 NEG 操作码。
GCC 6.1 或 Clang 仅在调用 int 版本时才会崩溃。 但当它们为无符号长版本发出 SUB 操作码时,它们都避免了崩溃。
他们可以这样做吗?
最佳答案
[编辑]这是问题先前版本的答案,它显示了使用参数 dist==1
调用这些函数时出现的问题
-(unsigned long)1
定义明确且环绕。只是ULONG_MAX
。出于同样的原因,-(unsigned int)
是 UINT_MAX
。
数组边界之外的指针运算会导致未定义的行为,因此 GCC 忽略这种可能性是完全合理的。例如,他们可以将 x64 上的指针视为带有环绕的 64 位整数。将 64 位 ULONG_MAX
添加到具有环绕功能的 64 位指针只会将指针减少 -1,这就是环绕的工作原理。添加 32 位 UINT_MAX
点与您的 int[100]
相差甚远。
因此,您看到的行为是未定义行为的一个完全有效的结果。然而它是完全不可靠的。优化器可能知道您添加的元素数量不能超过数组中允许的最大数量(64 位平台上的 4 字节整数为 2^62),并据此进行假设。
关于c++ - 使用无符号 "negative"数字递减指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45191362/