博客转载请注明原地址: 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对比a
与ebp-1Ch
的值,可以发现它们相等,也就证明了我们上面的对应关系,总结出编译器对于数组的解释:
ptr [数组首地址 + 数组下标 * sizeof(变量类型)]
貌似这个结论,比较显然,但是如果按照这个结论来看:
- a[3]翻译为: ptr [ a + 3 * sizeof(int) ]
- 3[a]翻译为: ptr [ 3 + a * sizeof(int) ]
如此来看,两者不应该是一样的,但是实际运行程序发现,两者确实相等。这让我们感觉到编译器非常聪明,能够识别出
a
才是真正的数组首地址,3
才是真正的数组下标。考虑到编译器的才能是由我们程序员所赋予,显然其无法真正识别出谁是数组首地址,而是通过预设的指导规则得到。在这里,
3
与a
,对编译器来讲,前者是一个常数,后者是一个指针变量。从更高层次来看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: 非法索引,不允许间接寻址
至此问题分析完毕,总结如下:
- a[i] 与 i[a]的含义一样
- 数组a[i]被解释为: ptr [数组首地址 + 下标 * sizeof(变量类型)]
- 表达式中必须出现一个指针变量,无论其位置如何,其被视为数组首地址,剩余的值作为数组下标
版权声明:本文为博主原创文章,未经博主允许不得转载。 博客原址:http://blog.csdn.net/sunliymonkey