码迷,mamicode.com
首页 > 编程语言 > 详细

在c/c++语言中,为什么c[5] == 5[c]

时间:2015-09-01 10:48:26      阅读:313      评论:0      收藏:0      [点我收藏+]

标签:c   c++   反汇编   问题分析   

博客转载请注明原地址: http://blog.csdn.net/sunliymonkey/article/details/48139183

问题:在c/c++语言中,为什么c[5] == 5[c]?

  这个问题,当初是在德问上看见的,起初自己也不知道其机理,猜测与c语言的编译机制有关,于是通过反汇编、猜测、验证,最终找到了原由。

下面是我分析该问题的过程,首先来看一段关于数组的代码:

#include<iostream>
using namespace std;
int main()
{
    int a[5];
    for(int i = 1; i < 5; i++)
    {   
        a[i] = i + 5;
    }
    a[3] = 11;
    3[a] = 15;
    cout << a[3] << endl;
    system("pause");
    return 0;
}   

使用Microsoft Visual 2010对代码进行反汇编:

7:  {   
8:      a[i] = i + 5;
00251B80 8B 45 D8      mov   eax,dword ptr [i]  
00251B83 83 C0 05      add   eax,5              // eax = i + 5
00251B86 8B 4D D8      mov   ecx,dword ptr [i]  // 用ecx存放a[i]下标i的值
00251B89 89 44 8D E4   mov  dword ptr [ebp+ecx*4-1Ch],eax // 将eax的值传给a[i]  
9: }

根据上面的汇编代码,我们可以发现编译器对于a[i]的汇编表示:

    a[i]:  dword ptr [ebp+ecx*4-1Ch]

  其中dword,表示双字(四个字节);ptr,pointer缩写,表示指针;[addr]中的addr表示地址位置。整个式子表示从位于ebp+ecx*4-1Ch的地址处,提取变量大小为4个字节的变量值,与a[i]进行对比,可以猜测:

    a[i]    <--->    [ebp+ecx*4-1Ch]
    a       <--->    ebp - 1Ch   //数组首地址
    i       <--->    ecx         //数组下标
    int     <--->    4           //变量大小

技术分享

通过Microsoft Visual 2010对比aebp-1Ch的值,可以发现它们相等,也就证明了我们上面的对应关系,总结出编译器对于数组的解释:

    ptr [数组首地址 + 数组下标 * sizeof(变量类型)]

貌似这个结论,比较显然,但是如果按照这个结论来看:

  • a[3]翻译为: ptr [ a + 3 * sizeof(int) ]

  • 3[a]翻译为: ptr [ 3 + a * sizeof(int) ]

      如此来看,两者不应该是一样的,但是实际运行程序发现,两者确实相等。这让我们感觉到编译器非常聪明,能够识别出a才是真正的数组首地址,3才是真正的数组下标。考虑到编译器的才能是由我们程序员所赋予,显然其无法真正识别出谁是数组首地址,而是通过预设的指导规则得到。

      在这里,3a,对编译器来讲,前者是一个常数,后者是一个指针变量。从更高层次来看a[i][i]a,两者均为变量,不过其中一个是整数类型,另外一个是指针类型。能够猜测到,编译器应该是将指针变量识别为数组首地址,而剩余的变量值作为数组下标

接下来我们做以下实验进行验证:

    int a[5];
    int *p = a;
    int i = 2 , b = &a;
    //a: 数组首地址
    i[a] = 1;   // 正确
    2[a] = 1;   // 正确
    (i+2)[a+1]=1; // 正确

    //p: int指针变量
    i[p] = 1;   // 正确
    2[p] = 1;   // 正确
    (i+2)[p+1]=1; // 正确

    //无指针变量
    b[2] = 3;   // 失败 error C2109: 下标要求数组或指针类型
    2[b] = 4;   // 失败 error C2109: 下标要求数组或指针类型
    i[b] = 5;   // 失败 error C2109: 下标要求数组或指针类型
    b[i] = 6;   // 失败 error C2109: 下标要求数组或指针类型

  因此编译器对于数组的处理时,必须要有一个指针变量作为基址,其它数值作为数组下标。你可能不禁会问:如果存在两个指针变量,怎么办? 按照上面的推测,存在两个指针变量,编译器貌似是无法处理的,实验验证也表明,存在多个指针变量,将会报错:

    int a[5],b[5];
    a[b+2] = 4;  // 失败  error C2107: 非法索引,不允许间接寻址

至此问题分析完毕,总结如下:

  1. a[i] 与 i[a]的含义一样

  2. 数组a[i]被解释为: ptr [数组首地址 + 下标 * sizeof(变量类型)]

  3. 表达式中必须出现一个指针变量,无论其位置如何,其被视为数组首地址,剩余的值作为数组下标

版权声明:本文为博主原创文章,未经博主允许不得转载。 博客原址:http://blog.csdn.net/sunliymonkey

在c/c++语言中,为什么c[5] == 5[c]

标签:c   c++   反汇编   问题分析   

原文地址:http://blog.csdn.net/sunliymonkey/article/details/48139183

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!