bor*_*oon 7 c arrays pointers boundary
我花了我的业余时间做一些测试,有趣的事情和实现一些各种各样的事情,如简单的算法,数据结构,这些天我个人的快乐....
但是,我最终找到了一些有趣的东西.我不知道为什么这个结果到现在才发生..
max_arr_count_index
根据arr[5]
值分配,该值超过数组+1的末尾.
有人可以向我解释这个吗?我知道不应该这样.我为数组的过去的一个索引赋值(这里,问题情况下arr [5] = 30)并且它不安全,并且它是标准定义的未定义行为.
我不会在真实领域做同样的事情,但是,我只是想在这里得到更多的内幕.
LLVM和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;
}
Run Code Online (Sandbox Code Playgroud)
下面没有问题的结果:
[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
Run Code Online (Sandbox Code Playgroud)
[问题案例:我指定了索引结束时的值]
#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;
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
[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
Run Code Online (Sandbox Code Playgroud)
访问数组超出范围会调用未定义的行为.在这种情况下,没有任何好处.大小arr
是5
.您可以访问arr
从arr[0]
到arr[4]
.
将UB暂时放在一边,解释行为
/* 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.
*/
Run Code Online (Sandbox Code Playgroud)
可能是变量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,那么所有的赌注都会被淘汰.
很明显,就C标准而言,这是未定义的行为,并且编译器可能会让你的恶魔飞出你的鼻子,这将是很好的.
但是你想要更深入,因为你要求"引擎盖下",所以我们基本上必须寻找汇编器输出.摘录(用gcc -g test test.c
和制作objdump -S --disassemble test
)是:
int main(int argc, const char * argv[]) {
743: 55 push %rbp
744: 48 89 e5 mov %rsp,%rbp
747: 48 83 ec 10 sub $0x10,%rsp
74b: 89 7d fc mov %edi,-0x4(%rbp)
74e: 48 89 75 f0 mov %rsi,-0x10(%rbp)
// insert code here...
printf("[before]max_arr_count_index : %d\n", max_arr_count_index);
752: 8b 05 fc 08 20 00 mov 0x2008fc(%rip),%eax # 201054 <max_arr_count_index>
758: 89 c6 mov %eax,%esi
75a: 48 8d 3d 37 01 00 00 lea 0x137(%rip),%rdi # 898 <_IO_stdin_used+0x18>
761: b8 00 00 00 00 mov $0x0,%eax
766: e8 35 fe ff ff callq 5a0 <printf@plt>
printf("[before]The original array elements are :\n");
76b: 48 8d 3d 4e 01 00 00 lea 0x14e(%rip),%rdi # 8c0 <_IO_stdin_used+0x40>
772: e8 19 fe ff ff callq 590 <puts@plt>
print_all_arr(arr);
777: 48 8d 3d c2 08 20 00 lea 0x2008c2(%rip),%rdi # 201040 <arr>
77e: e8 6d ff ff ff callq 6f0 <print_all_arr>
arr[0] = 1;
783: c7 05 b3 08 20 00 01 movl $0x1,0x2008b3(%rip) # 201040 <arr>
78a: 00 00 00
arr[1] = 2;
78d: c7 05 ad 08 20 00 02 movl $0x2,0x2008ad(%rip) # 201044 <arr+0x4>
794: 00 00 00
arr[2] = 3;
797: c7 05 a7 08 20 00 03 movl $0x3,0x2008a7(%rip) # 201048 <arr+0x8>
79e: 00 00 00
arr[3] = 4;
7a1: c7 05 a1 08 20 00 04 movl $0x4,0x2008a1(%rip) # 20104c <arr+0xc>
7a8: 00 00 00
arr[4] = 5;
7ab: c7 05 9b 08 20 00 05 movl $0x5,0x20089b(%rip) # 201050 <arr+0x10>
7b2: 00 00 00
/* 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;
7b5: c7 05 95 08 20 00 1e movl $0x1e,0x200895(%rip) # 201054 <max_arr_count_index>
7bc: 00 00 00
/* 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);
7bf: 8b 05 8f 08 20 00 mov 0x20088f(%rip),%eax # 201054 <max_arr_count_index>
7c5: 89 c6 mov %eax,%esi
7c7: 48 8d 3d 22 01 00 00 lea 0x122(%rip),%rdi # 8f0 <_IO_stdin_used+0x70>
7ce: b8 00 00 00 00 mov $0x0,%eax
7d3: e8 c8 fd ff ff callq 5a0 <printf@plt>
printf("[after]The array elements after insertion :\n");
7d8: 48 8d 3d 39 01 00 00 lea 0x139(%rip),%rdi # 918 <_IO_stdin_used+0x98>
7df: e8 ac fd ff ff callq 590 <puts@plt>
print_all_arr(arr);
7e4: 48 8d 3d 55 08 20 00 lea 0x200855(%rip),%rdi # 201040 <arr>
7eb: e8 00 ff ff ff callq 6f0 <print_all_arr>
return 0;
7f0: b8 00 00 00 00 mov $0x0,%eax
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,即使在那个级别,反汇编程序也已经知道您正在有效地进行设置max_arr_count_index
.但为什么?
这是因为通过GCC产生的内存布局是简单的方式(与我们用-g
用gcc
,使其嵌入调试信息,这样的反汇编可以知道哪个存储位置是场).你有一个包含五个整数的全局数组,以及一个彼此相继声明的全局int变量.全局int变量就在内存中的数组后面.因此,访问数组末尾后面的整数给出了max_arr_count_index
.
请记住,访问例如s i
的数组元素(至少在我所知的所有体系结构中)只是访问内存位置,其中是第一个元素的地址.arr
int
arr+sizeof(int)*i
arr
如上所述,这是未定义的行为.GCC还可以在数组之前对全局int变量进行排序,这会导致不同的效果,甚至程序在尝试访问时终止,arr[5]
如果该位置没有有效的内存页面.
归档时间: |
|
查看次数: |
197 次 |
最近记录: |