假设我有:
int test[10];
在 32 位机器上。如果我这样做怎么办:
int b = test[-1];
显然,在访问数组(越界)时这是一个很大的禁忌,但实际发生了什么?只是好奇
我是否在访问数组“之前”的 32 位字?
int b = *(test - 1);
或者只是解决一个非常遥远的单词(从“测试”内存位置开始)?
int b = *(test + 0xFFFFFFFF);
0xFFFFFFFF 是十进制 -1 的二进制补码表示
假设我有:
int test[10];
在 32 位机器上。如果我这样做怎么办:
int b = test[-1];
显然,在访问数组(越界)时这是一个很大的禁忌,但实际发生了什么?只是好奇
我是否在访问数组“之前”的 32 位字?
int b = *(test - 1);
或者只是解决一个非常遥远的单词(从“测试”内存位置开始)?
int b = *(test + 0xFFFFFFFF);
0xFFFFFFFF 是十进制 -1 的二进制补码表示
当您试图访问数组边界之外的元素时,程序的行为是未定义的。
可能发生的情况是:假设您有一个 32 位 int 类型,您在 test[0] 之前访问堆栈上的 32 位内存(如果有)并将其转换为 int。您的进程甚至可能不拥有此内存。不好。
无论发生什么,您都会得到未定义的行为,因为指针算术仅在数组中定义(包括最后一个位置)。
一个更好的问题可能是:
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
它在数组边界内。
C++ 标准说它是未定义的行为并且是非法的。这在实践中意味着任何事情都可能发生,并且任何事情都可能因硬件、编译器、选项以及您能想到的任何其他事情而有所不同。由于任何事情都可能发生,因此推测特定硬件/编译器组合可能会发生什么并没有多大意义。
官方的回答是行为未定义。非正式地,您试图在数组开始之前访问整数。这意味着您指示计算机计算数组开头之前 4 个字节的地址(在您的情况下)。此操作是否成功取决于多种因素。其中一些是数组是否将分配在堆栈段或静态数据段上,具体来说该地址的位置将在哪里。在通用机器(windows/linux)上,您可能会得到一个垃圾值,但如果地址恰好位于进程无权访问的某个地方,它也可能导致内存冲突错误。任何人都可以猜测专用硬件上可能发生的事情。