realloc在不同编译环境下的不一致问题
我们知道realloc是在原有地址空间下重新分配地址空间大小,原先已经写在地址中的数据,在函数执行后会再写入新分配的空间中去,笔者抱着试一试的心态编写代码实验,发现了一些问题与原因探索与读者分享。
#include<stdio.h>
#include<stdlib.h>
int main(){
int i,len = 10;
int *a = (int *)malloc(sizeof(int) * len);
for(i = 0;i < len;i++){
a[i] = i;
}
realloc(a,20);
len = 20;
for(i = 0;i < len;i++){
printf("%d ",a[i]);
}
free(a);
return 0;
}
下面这张图是在dev c++里面执行出的结果
下面这张图是vc2010编译器执行出的结果
与我们原先认为的有分歧的情况出现vc2010中,下面对上面程序的反汇编程序进行分析
值得一提的是,vc用的是X86架构下的汇编语言
下面是两条关键程序的汇编代码
int *a = (int *)malloc(sizeof(int) * len);
00AA34A5 mov eax,dword ptr [len]
00AA34A8 shl eax,2
00AA34AB mov esi,esp
00AA34AD push eax
00AA34AE call dword ptr [__imp__malloc (0AA82B0h)]
00AA34B4 add esp,4
00AA34B7 cmp esi,esp
00AA34B9 call @ILT+300(__RTC_CheckEsp) (0AA1131h)
00AA34BE mov dword ptr [a],eax
realloc(a,20);
00AA34E9 mov esi,esp
00AA34EB push 14h
00AA34ED mov eax,dword ptr [a]
00AA34F0 push eax
00AA34F1 call dword ptr [__imp__realloc (0AA82B4h)]
00AA34F7 add esp,8
00AA34FA cmp esi,esp
00AA34FC call @ILT+300(__RTC_CheckEsp) (0AA1131h)
可以看到,真正的内核函数并不存在于这里,命令还是有继续调用malloc和realloc的内部命令的,再将程序跳转到对应的目标地址(这里笔者重新编译了,所以地址会有变化,但汇编的内容是一样的)。
__imp__malloc:
00CF82B0 push eax
00CF82B1 nop
00CF82B2 jo __imp__free+52h (0CF830Eh)
__imp__realloc:
00CF82B4 xor byte ptr [ebx+7EF05A71h],cl
00CF82BA pop edx
可以看到realloc只有异或操作,并没有实际的赋值操作。
其中c1的值是8,ascii的值是56,但是是一个字节的异或
__RTC_CheckEsp是检查内存溢出的命令,程序的反汇编无法到达这条命令的地址。
所以推断问题是出在异或中了,但问题在于1个字节的异或不可能改变这么多信息的,一个int就占了4字节,很是不理解,感觉很有毒。但由于笔者能力有限,只能探索到这,如果读者有所发现可以一起探讨,这就属于科研生活中的小插曲了。
补充:这里出现的问题与后面申请数值指针无关,首先内存空间一般够用且去掉后面的代码问题仍在。很遗憾devc++没有反汇编的功能,不能进行对比。当然也有可能问题只出现在我这里,因为安装的原因,编译器的原因等等,可能在读者的编译环境下就运行正常了,也不是不可能,只能说这个问题太硬。
下面再补充一些冷知识,就不再重新写一篇blog了,其实都归属于指针部分的内容,写在一起也无伤大雅。
数组指针
这是在动态二维数组的申明中看到的,这里记录一下
数字指针顾名思义,其元素内容就是指针地址
指针数组见C程序涉及的307页
int (*b)[2]=(int(*)[2])malloc(sizeof(int));
printf("\n%d",b[100]);
而且有趣的一点现象是,当访问动态数组的下标超过原有的数组大小时,不会发生地址越界,而是访问到一段以原地址加上地址偏移量为地址的内容(当然我们没有定义过,访问一段没受限制的内存)