取消引用指针和访问数组元素之间的区别 [英] Difference between dereferencing pointer and accessing array elements

查看:214
本文介绍了取消引用指针和访问数组元素之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我记得在哪里指针和数组之间的差异被证明的例子。

数组衰变的指针在当作为函数参数传递数组的第一个元素,但它们是不等同,下所证明:

//文件fil​​e1.c中诠释一个[2] = {800,801};
INT B〔2] = {100,101};

//文件fil​​e2.c中的extern int类型的[2];//这里b的声明为指针,
//虽然外部单元将它定义为一个阵列
EXTERN INT * B;诠释主(){  INT X1,X2;  X1 =一个[1]; // 好
  X2 = B [1]; //在运行时崩溃  返回0;
}

链接器不为外部变量的类型检查,以便在编译时生成错误。问题是, B 其实是一个数组,但是编译单元文件2 不知道这一点,并治疗 b 为指针,从而导致崩溃试图取消引用它的时候。

我记得这个解释是非常有意义的,但现在我不记得的解释我也不能上来就对我自己的。

所以我想这个问题是怎么一个数组访问元素时,区别对待不是一个指针? (因为我认为 P [1] 转换为(大会当量) *(P + 1)不管 p 是一个数组或一个指针 - 我显然是错误的)


由两个指针引用(VS 2013)生成的程序集:结果
注: 1158000h 1158008h 的内存地址的 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在评论中提供的链接:<一个href=\"http://books.google.com.au/books?id=4vm2xK3yn34C&printsec=frontcover&dq=Deep%20C%20secrets&hl=en&sa=X&ei=-j4KU9L5Ec3jkgWblYHoAg&ved=0CC0Q6AEwAA#v=onepage&q=extern%20&f=false\"相对=nofollow> C专家编程:深度C秘密(96页),我想出了一个简单的答案(一个简单的哑下来书中的解释版本;一个完整的学术答案读的书):


  • 公布时, int类型的[2]

    • 编译器为 A 其中,该变量存储的地址。这个地址也是数组的地址自变量的类型是阵列。

    • 访问 A [1] 表示:

      • 检索该地址,

      • 添加偏移和

      • 在此计算的新地址访问存储器。



  • 公布时, INT * B

    • 编译器也有一个地址 B 但这是指针变量的地址,而不是数组。

    • 所以访问 B [1] 表示:

      • 检索该地址,

      • 访问该位置获得的值b ,即阵列
      • 地址
      • 添加一个偏移到这个地址,然后

      • 访问最终的存储单元。



I remember an example where the difference between pointers and arrays was demonstrated.

An array decays to a pointer to the first element in an array when passed as a function parameter, but they are not equivalent, as demonstrated next:

//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;
}

The linker does not type-check for external variables so no errors are generated at compile time. The problem is that b is in fact an array, but the compilation unit file2 is unaware of that and treats b as a pointer, resulting in a crash when trying to dereference it.

I remember when this was explained it made perfect sense, but now I can't remember the explanation nor I can come up to it on my own.

So I guess the question is how is an array treated differently than a pointer when accessing elements? (because I thought that p[1] is converted to (the assembly equivalent of) *(p + 1) regardless if p is an array or a pointer — I am obviously wrong).


The assembly generated by the two dereferences (VS 2013):
note: 1158000h and 1158008h are the memory addresses of a and b respectively

    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  

解决方案

Thanks to the link provided by @tesseract in the comments: Expert C Programming: Deep C Secrets (page 96), I came up with a simple answer (a simple dumb down version of the explanation in the book; for a full academic answer read the book):

  • when declared int a[2]:
    • the compiler has for a an address where this variable is stored. This address is also the address of the array since the type of the variable is array.
    • Accessing a[1] means:
      • retrieving that address,
      • adding the offset and
      • accessing the memory at this computed new address.
  • when declared int *b:
    • the compiler also has an address for b but this is the address of the pointer variable, not the array.
    • So accessing b[1] means:
      • retrieving that address,
      • accessing that location to get the value of b, i.e. the address of the array
      • adding an offset to this address and then
      • accessing the final memory location.

这篇关于取消引用指针和访问数组元素之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆