这个问题在这里已有答案:
所以我有一个程序
#include "main.h"
#import <limits.h>
#import <stdint.h>
int foo(const void *src, void *dst, uint16_t len)
{
uint16_t index;
const uint8_t *srcRef = src;
uint8_t *dstRef = dst;
for(index = 0; index <= len; index++)
{
dstRef[index] = srcRef[index];
printf("-> %d - %d\n", index, srcRef[index]);
}
printf("%d\n", index);
return 0;
}
int main()
{
printf("max length of UInt16 is : %d\n", UINT16_MAX);
uint8_t arrOr[55];
uint8_t arr[55];
arrOr[54] = 7;
uint16_t len = 119;
foo(arrOr, arr, len);
return 0;
}
程序能够访问数组索引超出范围是否正常? (我实际上期待它崩溃)当数组长度为55时,它最多可以访问119(120次崩溃)。
当它是56时,我仍然只能访问最多119次和120次崩溃
当它是57时,我最多可以访问135次和136次崩溃。
我想它正在尝试访问整个程序的内存地址,而不仅仅是数组索引。但是当我将数组长度更改为57时实际发生了什么,这让我可以通过将其增加到56来访问更多我无法做到的地址?
看起来像对齐很重要。
首先,这是undefined behavior所以不要依赖它。根据ISO C标准,访问越界是UB。
再次警告:以下任何内容都是高度依赖于实现的。由您自行决定。
好吧,先回答。你的猜测是正确的:
我想它正在尝试访问整个程序的内存地址,而不仅仅是数组索引。
有点有趣的是你的数字120
和136
相差16,所以我猜它是由8的对齐引起的(你有2个数组)。在现代计算机中,内存中的数据与性能问题保持一致。对于典型的64位系统,它与8对齐,因此两个数组arr
和arrOr
都对齐到8个字节。也就是说,当你声明一个57的大小时,它实际上占用了64个字节的内存(所以如果你声明一个介于57和64之间的大小,你将不会发现任何差异,但如果你的大小是65,你将会看到它)。
对于大于64的额外空间,可能是因为调用堆栈。这意味着您正在访问父函数中的变量,如main
或WinMain
或上述任何内容。程序启动时系统定义了一些变量(在Windows上为hInstance
,commandLine
,hPrevInstance
等)。当您访问甚至修改这些内存区域时,您可能会破坏您的程序甚至整个系统。再次,这是访问越界的原因之一。
最后一行(允许我的重复说明,因为它很重要),这是依赖于实现的,并且当您在另一个平台甚至同一平台的不同版本上编译代码时可能会发生变化。
顺便说一句,#import
不是标准的预处理器指示。它(很可能)只有in Visual Studio 2017。以后不要这样做。我猜你基于该代码在Windows上使用VS 2017。
你定义的数组和索引是
uint8_t arrOr [55];
uint8_t arr [55];
index = 119;
这是数组之外的所以你需要减少索引值或增加你的数组大小,以便它访问内存位置值,即垃圾或一些时间分段错误
// accessing array out of bounds
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5};
printf("arr [0] is %d\n",arr[0]);
printf("arr[10] is %d\n",arr[10]);
// allocation memory to out of bound
// element
arr[10] = 11;
printf("arr[10] is %d\n",arr[10]);
return 0;
}
输出:运行时错误:分段错误(SIGSEGV)
重点:
- 在C编程中保留在数组边界内,同时使用数组来避免任何此类错误。 -C ++但是提供了std :: vector类模板,它不需要执行边界检查。向量还具有std :: at()成员函数,该函数可以执行边界检查。
对于java,您可以轻松使用这些异常
java.lang.ArrayIndexOutOfBoundsException