c++ - 使用无符号 "negative"数字递减指针

标签 c++ c gcc

下面的示例在调用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/

相关文章:

c - 从文本文件中随机配对团队两次

c - 默认包含路径 Glibc

linux - 在 Linux 的可执行文件中嵌入数据时如何控制符号名称?

c++ - 对标准随机生成器类型的 undefined reference

c++ - 多 Blob 跟踪

c++ - 如何从 lldb 执行函数(由指针标识)

c++ - 如何在 Mac 上使用 openGL 和 gcc?

c++ - catch (domain_error const & x) 和 catch (const domain_error & x) 之间的区别

无法捕获 C 中的击键 [Ubuntu 16.04LTS]

困惑为什么代码不能正确运行