C++数组超出范围访问以计算指针有效?

C++ Array out of Range access to calculate pointer valid?

本文关键字:计算 指针 有效 访问 数组 范围 C++      更新时间:2023-10-16

以下代码是否保证有效?

int* arr = new int[2];
std::cout << &arr[0x100];

这被认为是好的做法,还是以常规方式添加偏移量会更干净?

编辑:通过"工作",我的意思是它应该在0x100打印指向理论成员的指针。基本上,如果这等价于"std::cout <<((unsigned int)arr + 0x100*sizeof(int));"。

使用我的编译器(Cygwin GCC)获取此值的地址与执行指针算术相同,尽管每个都是未定义的行为(UB)。正如 Jen 在下面的评论中提到的,在 http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html,我发现以下内容很有帮助。

同样值得指出的是,Clang和GCC都确定了C标准未定义的一些行为。我将描述的内容根据标准都是未定义的,并且被这两个编译器在其默认模式下视为未定义的行为。

取消引用野生指针和越界数组访问:取消引用随机指针(如 NULL、指向释放内存的指针等)和越界访问数组的特殊情况是 C 应用程序中的常见错误,希望不需要解释。为了消除这种未定义行为的来源,必须对每个数组访问进行范围检查,并且必须更改 ABI,以确保范围信息遵循任何可能受指针算术影响的指针。对于许多数值和其他应用程序来说,这将产生极高的成本,并且会破坏与每个现有 C 库的二进制兼容性。

指针算法也是 UB。所以你有一个地址,但你不能取消引用指向它的指针。所以拥有这个地址真的没有用。仅获取地址是 UB,不应在代码中使用。

有关越界指针,请参阅此答案: 为什么越界指针算术是未定义的行为?

我的示例代码:

int* arr = new int[2];
std::cout << arr << std::endl;
std::cout << &(arr[0])<< std::endl;
std::cout << &(arr[1])<< std::endl;
std::cout << &arr[0x100] << std::endl; // UB, cannot be dereferenced
std::cout << &arr[256] << std::endl;   // cannot be dereferenced, so no use in having it
std::cout << arr + 0x100; // UB here too, no use in having this address 

示例输出:

0x60003ae50
0x60003ae50
0x60003ae54
0x60003b250
0x60003b250
0x60003b250

在第一行中分配 2 个整数值。在第二行中,您访问此范围之外的内存。这是完全不允许的。

编辑:这里有一些有趣的评论。但我不明白,为什么需要引用这么简单答案的标准,为什么这里讨论这么多指针算术?

从逻辑角度来看,std::cout <<&arr[0x100] 包含 3 个步骤: 1. 访问数组中不存在的成员 2. 获取不存在成员的地址 3. 使用不存在的成员的地址

如果第一步无效,以下不是所有未定义吗?