从编译器的角度去观察数组

刚学复习完c语言数组。。现在来总结一下编译器是怎么处理数组的。
我用的是vs2013,其他编译器处理数组的方法可能不一样

//c语言代码
int main()
{
        //数组名:arr   元素个数:5
    int arr[5] = { 1, 2, 3, 4, 5 };
    arr[3] = 9; //修改第四个元素的值
    return 0;
}
//汇编代码

//开辟栈空间
001F3050  push        ebp  
001F3051  mov         ebp,esp  
001F3053  sub         esp,0DCh  
//保存需要用到的寄存器
001F3059  push        ebx  
001F305A  push        esi  
001F305B  push        edi  
//填充堆栈缓冲区
001F305C  lea         edi,[ebp+FFFFFF24h]  
001F3062  mov         ecx,37h  
001F3067  mov         eax,0CCCCCCCCh  
001F306C  rep stos    dword ptr es:[edi]  
//分别把每个元素赋值到对应的内存地址
001F306E  mov         dword ptr [ebp-18h],1  
001F3075  mov         dword ptr [ebp-14h],2  
001F307C  mov         dword ptr [ebp-10h],3  
001F3083  mov         dword ptr [ebp-0Ch],4  
001F308A  mov         dword ptr [ebp-8],5  
//这里是修改第四个元素的值
013F2331  mov         eax,4  //这个4是int数据类型的大小
013F2336  imul        ecx,eax,3  //这个3是数组下标  
//ecx存的是4字节*第3个数组下标得到的结果是十六进制的C

013F2339  mov         dword ptr [ebp+ecx-18h],0  //把0赋值给arr[3]
//这里为什么是[ebp+ecx-18h]呢,看上面[ebp-18h]存的第一个元素的值吧
//因为18h-0xC=C,所以也就是第四个元素的内存地址[ebp-0Ch]

//还原寄存器 
001F30A4  pop         edi  
001F30A5  pop         esi  
001F30A6  pop         ebx  
001F30A7  mov         esp,ebp  //还原栈顶
001F30A9  pop         ebp  
001F30AA  ret  //函数返回

上面是一维数组的c语言代码和汇编代码
编译器只是将数组的每个元素放到对应的内存空间中
应该很简单吧........

现在在来看看二维数组编译器是如何处理的

int main()
{
    int arr[3][5] = { 
        { 1, 2, 3, 4, 5 },
        { 6, 7, 8, 9, 10 },
        { 11, 12,13, 14, 15 }
    };
    arr[2][3] = 21;
    return 0;
}
//汇编代码

//上面解释过的 我就不再次说了
00C222F0  push        ebp  
00C222F1  mov         ebp,esp  
00C222F3  sub         esp,104h  
00C222F9  push        ebx  
00C222FA  push        esi  
00C222FB  push        edi  
00C222FC  lea         edi,[ebp+FFFFFEFCh]  
00C22302  mov         ecx,41h  
00C22307  mov         eax,0CCCCCCCCh  
00C2230C  rep stos    dword ptr es:[edi] 
//分别把每个元素赋值到对应的内存地址
00C2230E  mov         dword ptr [ebp-40h],1  
00C22315  mov         dword ptr [ebp-3Ch],2  
00C2231C  mov         dword ptr [ebp-38h],3  
00C22323  mov         dword ptr [ebp-34h],4  
00C2232A  mov         dword ptr [ebp-30h],5  
00C22331  mov         dword ptr [ebp-2Ch],6  
00C22338  mov         dword ptr [ebp-28h],7  
00C2233F  mov         dword ptr [ebp-24h],8  
00C22346  mov         dword ptr [ebp-20h],9  
00C2234D  mov         dword ptr [ebp-1Ch],0Ah  
00C22354  mov         dword ptr [ebp-18h],0Bh  
00C2235B  mov         dword ptr [ebp-14h],0Ch  
00C22362  mov         dword ptr [ebp-10h],0Dh  
00C22369  mov         dword ptr [ebp-0Ch],0Eh  
00C22370  mov         dword ptr [ebp-8],0Fh  

//这里的14h是arr[3][5]中的5个元素类型的大小 5*sizeof(int)=14h 注意是十六进制的
02C2377  mov         eax,14h   
//把14h进行左移1位
002C237C  shl         eax,1  
//ecx=[ebp-18h]的内存地址,也就知道了arr数组的行数
002C237E  lea         ecx,[ebp+eax-40h]  

002C2382  mov         edx,4    //4就是4个字节因为int类型的大小为4字节
002C2387  imul        eax,edx,3  //eax存放的是arr数组的列数

//因为ecx相当于行数,虽然它是一个地址 。eax相当于列数
//可以计算一下ecx==[ebp-18h] eax==C
//[ecx+eax]==[ebp-18h+0xC]结果等于 [ebp-0Ch]   别告诉我你不会算-.-!
002C238A  mov         dword ptr [ecx+eax],15h  //然后赋值为21 十进制的...

00C2238A  pop         edi  
00C2238B  pop         esi  
00C2238C  pop         ebx  
00C2238D  mov         esp,ebp  
00C2238F  pop         ebp  
00C22390  ret  

所以呢。。不管在c语言里定义的数组是几维的,编译器会统统看做一维数组来处理的。。
读者若是发现了什么错误,还请多多帮忙指正。。毕竟我也只是个菜鸟。。。

你可能感兴趣的:(从编译器的角度去观察数组)