这些天来,我把业余时间都花在了做一些有趣的事情上,让自己在C语言中感到快乐......
但是,我最终发现了一些有趣的事情,我不知道为什么这个结果直到现在才发生。
根据arr[5]
值分配max_arr_count_index
,该值超出数组末尾+1。
有人能给我解释一下吗?我知道不应该这样,我给数组的过去一个索引赋值(这里,arr[5] = 30),这是不安全的,而且是标准定义的undefined behavior。
我不会在真实的中做同样的事,但是,我只想了解更多.
Clang和GCC给了我同样的结果。
代码和结果如下:
[无问题案例:我不分配索引末尾之后的值]
#include <stdio.h>
int arr[] = {11,33,55,77,88};
int max_arr_count_index = (sizeof(arr) / sizeof(arr[0]));
// print all
void print_all_arr(int* arr)
{
// just print all arr datas regarding index.
for(int i = 0; i < max_arr_count_index; i++) {
printf("arr[%d] = %d \n", i, arr[i]);
}
}
int main(int argc, const char * argv[]) {
// insert code here...
printf("[before]max_arr_count_index : %d\n", max_arr_count_index);
printf("[before]The original array elements are :\n");
print_all_arr(arr);
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
// arr[5] = 1000;
printf("[after]max_arr_count_index : %d\n", max_arr_count_index);
printf("[after]The array elements after :\n");
print_all_arr(arr);
return 0;
}
无问题结果如下:
[before]max_arr_count_index : 5
[before]The original array elements are :
arr[0] = 11
arr[1] = 33
arr[2] = 55
arr[3] = 77
arr[4] = 88
[after]max_arr_count_index : 5
[after]The array elements after :
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5
Program ended with exit code: 0
[问题案例:我分配的值超过了索引的结尾]
#include <stdio.h>
int arr[] = {11,33,55,77,88};
int max_arr_count_index = (sizeof(arr) / sizeof(arr[0]));
// print all
void print_all_arr(int* arr)
{
// just print all arr datas regarding index.
for(int i = 0; i < max_arr_count_index; i++) {
printf("arr[%d] = %d \n", i, arr[i]);
}
}
int main(int argc, const char * argv[]) {
// insert code here...
printf("[before]max_arr_count_index : %d\n", max_arr_count_index);
printf("[before]The original array elements are :\n");
print_all_arr(arr);
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
/* Point is this one.
If I assign arr[5] 30, then, max_arr_count_index is changed also as
30. if I assign arr[5] 10000 max_arr_count_index is assigned 10000.
*/
arr[5] = 30;
/* Point is this one.
If I assign arr[5] 30, then, max_arr_count_index is changed also as
30. if I assign arr[5] 10000 max_arr_count_index is assigned 10000.
*/
printf("[after]max_arr_count_index : %d\n", max_arr_count_index);
printf("[after]The array elements after arr[5] is assigned 30 :\n");
print_all_arr(arr);
return 0;
}
结果如下:
[before]max_arr_count_index : 5
[before]The original array elements are :
arr[0] = 11
arr[1] = 33
arr[2] = 55
arr[3] = 77
arr[4] = 88
[after]max_arr_count_index : 30
[after]The array elements after arr[5] is assigned 30 :
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5
arr[5] = 30
arr[6] = 0
arr[7] = 0
arr[8] = 0
arr[9] = 0
arr[10] = 0
arr[11] = 0
arr[12] = 0
arr[13] = 0
arr[14] = 0
arr[15] = 0
arr[16] = 0
arr[17] = 0
arr[18] = 0
arr[19] = 0
arr[20] = 0
arr[21] = 0
arr[22] = 0
arr[23] = 0
arr[24] = 0
arr[25] = 0
arr[26] = 0
arr[27] = 0
arr[28] = 0
arr[29] = 0
Program ended with exit code: 0
4条答案
按热度按时间nwwlzxa71#
很明显,就C标准而言,这是未定义的行为,编译器可以make fly demons out of your nose,它会很好。
但是如果您想深入了解,就像您要求的“引擎盖下”一样,那么我们实际上必须查找汇编器的输出。摘录(使用
gcc -g test test.c
和objdump -S --disassemble test
生成)如下:正如您所看到的,即使在这个级别,反汇编器也已经知道您正在有效地设置
max_arr_count_index
。这是因为GCC产生的内存布局就是这样(并且我们将
-g
与gcc
一起使用,使其嵌入调试信息,以便反汇编器可以知道哪个内存位置是哪个字段)。您有一个包含五个int的全局数组,以及一个全局int变量,全局int变量就在内存中数组的后面,访问数组末尾后面的整数得到max_arr_count_index
。请记住,对例如
int
s的数组arr
的元素i
的访问(至少在所有架构 I 已知上)是简单地访问存储器位置arr+sizeof(int)*i
,其中arr
是第一个元素的地址。如前所述,这是一个未定义的行为。GCC也可以将全局int变量置于数组之前,这将导致不同的效果,甚至可能在试图访问
arr[5]
时,如果该位置没有有效的内存页面,程序将终止。7vux5j2d2#
访问超出界限的数组会调用未定义的行为。在这种情况下不会有什么好结果。
arr
的大小为5
。您可以从arr[0]
到arr[4]
访问arr
。先把UB放在一边,对这种行为的解释
可能是变量
max_arr_count_index
声明在数组arr
之后。编译器可能为max_arr_count_index
分配的内存刚好超过数组arr
的最后一个元素。例如,如果arr[4]
在0x100
,那么max_arr_count_index
的内存分配在0x104
,所以数组arr
后面是地址0x104
。由于&arr[5]
和max_arr_count_index
是同一个地址,所以给arr[5]
赋值,并将该值写入max_arr_count_index
的地址。请注意,这并不是实际发生的事情。这是对这种行为的直觉。一旦出现UB,所有的赌注都将结束。rur96b6h3#
您在
arr
之后声明了max_arr_count_index
,因此max_arr_count_index
可能位于相对于arr
的下一个地址中,因此对arr+5
的赋值就是对max_arr_count_index
地址的赋值。fjaof16o4#
回答为什么“未定义的行为”会以某种方式起作用的问题是矛盾的,也是投反对票的秘诀。但鉴于我已经达到了今天的声誉上限,因此我对这一点要放松得多,以下是我的信:
arr[i]
的计算结果为*(arr + i)
。很明显,arr
和max_arr_count_index
之间可能没有填充,因此arr + 5
可能等于&max_arr_count_index
。但指针算法仅在数组中有效。您可以将指针设置为超过数组末尾的指针,但 * 取消引用 * 时的行为是 undefined。当然,再过一天,编译器可能会吃掉你的猫。