在反汇编观察后,你会发现:指针变量就是块内存区域,里面存放的是地址,你可以通过这个地址访问其它内存。

                                               数组就是块连续的内存区域,里面连续排列着同样size的内存,多维数组也是一样的。

上述很简单,就不贴代码赘述了。

 

但人们一般纠结这样一个问题:数组名 是不是 一种指针?

也就是说arr[]的这个arr是不是一种指针?

 

这个问题之前csdn论坛上讨论的热火朝天:

http://bbs.csdn.net/topics/380226723

http://blog.csdn.net/yby4769250/article/details/7294718#reply

 

一种看法就是把这个数组名当作一种特殊的指针来看待,特殊之处在于是常量,不能改变其指向的位置。

一种是透过C语言,从C语言编译之后的汇编,视角来看,认为数组名和指针在内存中完全不是一回事。

 

太认真考虑其定义和概念就接近于一种“玄学”,我这里就单纯讲反汇编角度来分析 数组名 和 指针在内存中的差别吧。

随便写的代码:

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

#include <stdio.h>

void func(int *p) {
    *(p+1) = 2;}

void main() {        int v = 1;        int *p = &v;        int v2 = *p + v;        int arr[100];        int v3 = arr[0] + v;        int v4 = *(arr+2) + v2;        func(arr);}

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

 

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

void main() {008114D0  push        ebp  
008114D1  mov         ebp,esp  
008114D3  sub         esp,298h  
008114D9  push        ebx  
008114DA  push        esi  
008114DB  push        edi  
008114DC  lea         edi,[ebp-298h]  
008114E2  mov         ecx,0A6h  
008114E7  mov         eax,0CCCCCCCCh  
008114EC  rep stos    dword ptr es:[edi]  
008114EE  mov         eax,dword ptr ds:[00818000h]  
008114F3  xor         eax,ebp  
008114F5  mov         dword ptr [ebp-4],eax  
        int v = 1;008114F8  mov         dword ptr [v],1  
        int *p = &v;008114FF  lea         eax,[v]  
00811502  mov         dword ptr [p],eax  
        int v2 = *p + v;00811505  mov         eax,dword ptr [p]  
00811508  mov         ecx,dword ptr [eax]  
0081150A  add         ecx,dword ptr [v]  
0081150D  mov         dword ptr [v2],ecx  
        int arr[100];        int v3 = arr[0] + v;00811510  mov         eax,4  00811515  imul        eax,eax,0  00811518  mov         ecx,dword ptr arr[eax]  
0081151F  add         ecx,dword ptr [v]  
00811522  mov         dword ptr [v3],ecx  
        int v4 = *(arr+2) + v2;00811528  mov         eax,dword ptr [ebp-1B4h]  
0081152E  add         eax,dword ptr [v2]  
00811531  mov         dword ptr [v4],eax  
        func(arr);00811537  lea         eax,[arr]  
0081153D  push        eax  
0081153E  call        func (0811226h)  
00811543  add         esp,4  }

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

 可以看到arr[100]这个数组名arr在汇编代码中变成了一个单纯的标号,代表一个地址,这个地址是     数组这一列连续内存空间的首地址。

假设数组地址是N,那么数组名在汇编代码中就是N本身。

 

但对比来看,指针在这里是栈空间上申请的内存。这块内存里存着别的内存的地址。

假设指针的地址是M,指针指向的内存的地址是N,那就是地址为M的内存里存着N。

 

二者对比 数组名和指针的差别就清楚了吧。一个就只是标号(地址),一个是一块内存,内存里面存着地址。

 

上述是讲数组名 和 指针的差别。

下面要讲,

而当数组作为函数参数时,其实就是转化为指针来玩的。

 

先讲调用函数时的反汇编代码(这里取数组地址,然后压入栈再call func):

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

        func(arr);
00811537  lea         eax,[arr]  
0081153D  push        eax  
0081153E  call        func (0811226h)  
00811543  add         esp,4

 

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

 

再讲func函数里面对数组操作的反汇编代码:

 

上面的代码的函数func:

void func(int *p) {    *(p+1) = 2;
}

反汇编代码为:

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

void func(int *p) {
00FA3DE0  push        ebp  
00FA3DE1  mov         ebp,esp  
00FA3DE3  sub         esp,0C0h  
00FA3DE9  push        ebx  
00FA3DEA  push        esi  
00FA3DEB  push        edi  
00FA3DEC  lea         edi,[ebp-0C0h]  
00FA3DF2  mov         ecx,30h  
00FA3DF7  mov         eax,0CCCCCCCCh  
00FA3DFC  rep stos    dword ptr es:[edi]  
    *(p+1) = 2;
00FA3DFE  mov         eax,dword ptr [p]  
00FA3E01  mov         dword ptr [eax+4],2  }
00FA3E08  pop         edi  
00FA3E09  pop         esi  
00FA3E0A  pop         ebx  
00FA3E0B  mov         esp,ebp  
00FA3E0D  pop         ebp  
00FA3E0E  ret

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

这里形参为指针,没什么异议。

 

改写一下,形参改为,arr[]的话:

void func(int arr[]) {
    arr[1] = 2;
}

 

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

void func(int arr[]) {
01173DE0  push        ebp  
01173DE1  mov         ebp,esp  
01173DE3  sub         esp,0C0h  
01173DE9  push        ebx  
01173DEA  push        esi  
01173DEB  push        edi  
01173DEC  lea         edi,[ebp-0C0h]  
01173DF2  mov         ecx,30h  
01173DF7  mov         eax,0CCCCCCCCh  
01173DFC  rep stos    dword ptr es:[edi]  
    arr[1] = 2;
01173DFE  mov         eax,4  01173E03  shl         eax,0  01173E06  mov         ecx,dword ptr [arr]  
01173E09  mov         dword ptr [ecx+eax],2  }
01173E10  pop         edi  
01173E11  pop         esi  
01173E12  pop         ebx  
01173E13  mov         esp,ebp  
01173E15  pop         ebp  
01173E16  ret

photoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训

 

可以看出二者(不管形参写成*p还是arr[])是没差别的。

数组作为函数参数,都是会被转化为指针来操作。

为何?

 

因为调用函数前压入栈的是数组的地址,而不是整个数组。这个地址存在栈空间里,占有一定内存,所以成了一个指针!

函数里面从栈里获取到这个指针,继续操作。

 

这样是有一定道理的,因为数组可能很长,如果整个压入栈就是从新复制了一份空间,可能非常浪费,还不如指向前一个栈空间里数组的内存。

 

 

 

最后我想说,我玩这个反汇编,似乎没啥实际用处,比如就算不懂数组名 和 指针差别,也可以写程序啊。

但我总觉得,作为一个程序员,搞明白自己写的程序,到底是怎么被计算机运行的,会非常TMD爽。而不只是单纯的会写。

所以我最近决定系统的玩一把反汇编。

让自己对自己写的任何一行C、C++代码都对其运行原理、内存都一清二楚,看到C、C++代码就能迅速想象出汇编代码的样子。

下一个课题:彻底搞明白,各种数据类型在内存中的存储,又要涉及补码了。hhh

http://www.cnblogs.com/rixiang/p/7121838.html