0

假设我有:

int test[10];

在 32 位机器上。如果我这样做怎么办:

int b = test[-1];

显然,在访问数组(越界)时这是一个很大的禁忌,但实际发生了什么?只是好奇

我是否在访问数组“之前”的 32 位字?

int b = *(test - 1);

或者只是解决一个非常遥远的单词(从“测试”内存位置开始)?

int b = *(test + 0xFFFFFFFF);

0xFFFFFFFF 是十进制 -1 的二进制补码表示

4

4 回答 4

2

当您试图访问数组边界之外的元素时,程序的行为是未定义的。

可能发生的情况是:假设您有一个 32 位 int 类型,您在 test[0] 之前访问堆栈上的 32 位内存(如果有)并将其转换为 int。您的进程甚至可能不拥有此内存。不好。

于 2013-05-15T14:56:48.097 回答
2

无论发生什么,您都会得到未定义的行为,因为指针算术仅在数组中定义(包括最后一个位置)。

一个更好的问题可能是:

int test[10];
int * t1 = test+1;
int b = t1[-1];      // Is this defined behaviour?

答案是肯定的。下标(C++11 5.2.1)的定义是:

表达式 E1[E2] 与 *((E1)+(E2)) 相同(根据定义)

所以这相当于*((t1)+(-1)). 指针加法的定义(C++11 5.7/5)适用于所有整数类型,有符号或无符号,所以不会导致-1转换为无符号类型;所以表达式等价于*(t1-1),这是定义明确的,因为t1-1它在数组边界内。

于 2013-05-15T15:07:45.510 回答
1

C++ 标准说它是未定义的行为并且是非法的。这在实践中意味着任何事情都可能发生,并且任何事情都可能因硬件、编译器、选项以及您能想到的任何其他事情而有所不同。由于任何事情都可能发生,因此推测特定硬件/编译器组合可能会发生什么并没有多大意义。

于 2013-05-15T14:57:10.990 回答
1

官方的回答是行为未定义。非正式地,您试图在数组开始之前访问整数。这意味着您指示计算机计算数组开头之前 4 个字节的地址(在您的情况下)。此操作是否成功取决于多种因素。其中一些是数组是否将分配在堆栈段或静态数据段上,具体来说该地址的位置将在哪里。在通用机器(windows/linux)上,您可能会得到一个垃圾值,但如果地址恰好位于进程无权访问的某个地方,它也可能导致内存冲突错误。任何人都可以猜测专用硬件上可能发生的事情。

于 2013-05-15T15:07:21.260 回答