取消引用指针和访问数组元素之间的区别

2024-01-06

我记得有一个例子演示了指针和数组之间的区别。

当作为函数参数传递时,数组会衰减为指向数组中第一个元素的指针,但它们并不等效,如下所示:

//file file1.c

int a[2] = {800, 801};
int b[2] = {100, 101};
//file file2.c

extern int a[2];

// here b is declared as pointer,
// although the external unit defines it as an array
extern int *b; 

int main() {

  int x1, x2;

  x1 = a[1]; // ok
  x2 = b[1]; // crash at runtime

  return 0;
}

链接器不会对外部变量进行类型检查,因此在编译时不会生成错误。问题是b其实是一个数组,只不过编译单元file2不知道这一点并对待b作为指针,在尝试取消引用它时会导致崩溃。

我记得当有人解释这一点时,这是完全有道理的,但现在我不记得解释了,我自己也无法想出它。

所以我想问题是在访问元素时数组与指针的处理方式有何不同? (因为我认为p[1]转换为(相当于的汇编)*(p + 1)不管如果p是数组还是指针——我显然错了)。


两次取消引用生成的程序集(VS 2013):
note: 1158000h and 1158008h是内存地址a and b分别

    12:   x1 = a[1];
0115139E  mov         eax,4  
011513A3  shl         eax,0  
011513A6  mov         ecx,dword ptr [eax+1158000h]  
011513AC  mov         dword ptr [x1],ecx  
    13:   x2 = b[1];
011513AF  mov         eax,4  
011513B4  shl         eax,0  
011513B7  mov         ecx,dword ptr ds:[1158008h]  
011513BD  mov         edx,dword ptr [ecx+eax]  
011513C0  mov         dword ptr [x2],edx  

感谢@tesseract 在评论中提供的链接:(第 96 页),我想出了一个简单的答案(书中解释的简单愚蠢版本;要获得完整的学术答案,请阅读本书):

  • when declared int a[2]:
    • 编译器有a存储该变量的地址。由于变量的类型是数组,因此该地址也是数组的地址。
    • Accessing a[1] means:
      • 检索该地址,
      • 添加偏移量并
      • 访问该计算出的新地址处的内存。
  • when declared int *b:
    • 编译器还有一个地址b但这是指针变量的地址,而不是数组。
    • So accessing b[1] means:
      • 检索该地址,
      • 访问该位置以获取值b,即数组的地址
      • 向该地址添加偏移量,然后
      • 访问最终的内存位置。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

取消引用指针和访问数组元素之间的区别 的相关文章

随机推荐