我对一个程序的分析(发现VC++的错误)

来源:互联网 发布:java函数调用数组 编辑:程序博客网 时间:2024/05/19 14:35
 

以下面程序分析入手:

int main()

{

       int a[5]={1,2,3,4,5};    

       int *ptr1=(int*)(&a+1);

       int *ptr2=(int*)((int)a+1);

       printf("%x,%x",ptr1[-1],ptr2);

       return 0;

}

 

下面用两种方法分析,第一,用理论分析;第二,在VC++6.0上调试,看结果。

第一,理论分析:

先看&a+1:对数组a的首地址,该地址的值加上sizeof(a)的值,即&a+5*sizeof(int),即下一个内存快的地址,也就是数组所在这块内存后面的那块的首地址(这个地址我们不知道是什么)。然后把这个地址强制转换为int型的指针,把这个指针赋给指针型变量ptr1.

下面分析ptr1[-1],ptr1[-1]= *(ptr1 - 1),(因为ptr1本身是指针变量,所以可以用作数组名)。由于ptr1是指针,指向数组a后面的下一个元素,而ptr1-1就是ptr1这个指针往前移动一个单位,移动之后这个指针指向了数组a的最后一个元素。显然,很正确。故*(ptr1-1)=5,显然,很正确。%x打印的是int型的值,即ptr1[-1]的值,即5。很正确。(实际上对于%x我不太明白)

下面分析ptr2:首先,a是数组首元素的首地址,(int)a即把这个地址强制转换为int型数据,然后(int)a+1很简单,就是int型数据的相加。(int*)((int)a+1)就是再把这个int型的数据再强制型转换为int类型的指针,最后再把这个指针赋给int型的ptr2指针。很简单。最后把这个指针给打印出来(以16进制数表示)。

 

第二,上面的理论分析很成熟,下面看在VC++6.0上的调试结果:

int main()

{

       int a[5]={1,2,3,4,5};      //a[5]=1245120。 a=0x0012ff6c(首地址),&a+1=0x0012ff6d,

                                           //&a+2=0x12ff6e,

       int *ptr1=(int*)(&a+1);   //a+1=0x0012ff70,a+2=0x0012ff74,

       int *ptr2=(int*)((int)a+1); //ptr1=0x0012ff80,ptr2=0x0012ff6d

       printf("%x,%x",ptr1[-1],ptr2);

       return 0;

}

调试情况大致正确,并且调试的最终结果和理论分析的最终结果是一样的。有一个疑问是,&a+1本来是数组所在这块内存后面的那块的首地址,但是调试器给出的却是错误的,或者我个人认为调试器把&a+1认为是&a直接加上int型的1,这样分析就正确。

其他的都比较正确,感觉这也是编译器的一个bug吧。