C++ 的指针和引用

0

Category : 编程知识

      我们在学习 C++ 的时候经常被告诫指针不是引用, 引用不是指针.

  今天我们来写一段小程序, 来一探究竟.

  1. 关于指针

  1#include <stdio.h>

  2

  3void main( void )

  4{

  5    int a = 20;

  6    int * b = &a;

  7    (*b) ++;

  8    printf(“==== %d ====\r\n”, *b);

  9}

  10看看我们对它编译后在调试器内的反汇编码:

  5:        int a = 20;

  00401028   mov         dword ptr [ebp-4],14h    ; // 为变量 a 赋值 14h(也就是十进制的 20), [ebp-4] 就代表变量 a

  6:        int * b = &a;

  0040102F   lea         eax,[ebp-4]                         ; // 取得变量 a 的地址

  00401032   mov         dword ptr [ebp-8],eax    ; // 将地址赋值给变量 b; 嗯, 是这个样子, 不离谱

  7:        (*b) ++;

  00401035   mov         ecx,dword ptr [ebp-8]    ; // [ebp-8] 代表变量 b

  00401038   mov         edx,dword ptr [ecx]        ; // 取得指针 b 的值, 存入 edx 寄存器

  0040103A   add         edx,1                                ; // 将 edx 寄存器的值增加 1

  0040103D   mov         eax,dword ptr [ebp-8]

  00401040   mov         dword ptr [eax],edx       ; // 将 edx 的值存回 b 指针所指的值

  8:        printf(“==== %d ====\r\n”, *b);

  00401042   mov         ecx,dword ptr [ebp-8]

  00401045   mov         edx,dword ptr [ecx]

  00401047   push        edx

  00401048   push        offset string “==== %d ====\r\n” (0042801c)

  0040104D   call        printf (004012a0)

  00401052   add         esp,8

  9:    }

  以上汇编码跟我们的常识符合.

  2. 关于引用

  1#include <stdio.h>

  2

  3void main( void )

  4{

  5    int a = 20;

  6    int & b = a;

  7    b ++;

  8    printf(“==== %d ====\r\n”, b);

  9}

  再来看看相应的汇编码:

  5:        int a = 20;

  00401028   mov         dword ptr [ebp-4],14h

  6:        int & b = a;

  0040102F   lea         eax,[ebp-4]

  00401032   mov         dword ptr [ebp-8],eax

  7:        b ++;

  00401035   mov         ecx,dword ptr [ebp-8]

  00401038   mov         edx,dword ptr [ecx]

  0040103A   add         edx,1

  0040103D   mov         eax,dword ptr [ebp-8]

  00401040   mov         dword ptr [eax],edx

  8:        printf(“==== %d ====\r\n”, b);

  00401042   mov         ecx,dword ptr [ebp-8]

  00401045   mov         edx,dword ptr [ecx]

  00401047   push        edx

  00401048   push        offset string “==== %d ====\r\n” (0042801c)

  0040104D   call        printf (004012a0)

  00401052   add         esp,8

  9:    }

  可以看出, 这两段汇编码完全一样.

  因此, 可以下结论了, 在汇编层面, 引用和指针是完全一样的东西. 咱们的教科书上的说法仅仅是语言层面的, 编译器的底层实现是有自己的逻辑的.

  经过试验, 数组的引用是不能作为函数的参数的, 例子如下:

  // 如果定义成如下这样, 将不能通过编译

  void RefAsParam(int & aRR[])

  {

  printf(“==== %d  == %d ====\r\n”, aRR[0], sizeof(aRR));

  }甚至也不能定义成这样:

  void RefAsParam(int & aRR[10])

  {

  printf(“==== %d  == %d ====\r\n”, aRR[0], sizeof(aRR));

  }而只能定义成这样:

  void RefAsParam(int aRR[])

  {

  printf(“==== %d  == %d ====\r\n”, aRR[0], sizeof(aRR));

  }或者这样 void RefAsParam(int aRR[10]), 但其中的sizeof(aRR) 的值等于4, 即一个指针的大小, 而不是 4*10=40 个字节.

  能通过编译且sizeof(aRR)等于 40 的的代码列出如下, 这定义的新类型定死了就是 10 个元素的数组, 相当没有灵活性.

  #include <stdio.h>

  // 只能定义成这样, 一个新类型, 含10个元素的整型数组

  typedef int MyArray[10];

  void RefAsParam(MyArray & aRR)

  {

  printf(“==== %d  == %d ====\r\n”, aRR[0], sizeof(aRR));

  }

  void main( void )

  {

  int a[10] = { 20, 30, 77 }; // 或者像这样:  MyArray a = {20, 30, 77};

  RefAsParam(a);

  }现在, 我们为了元素类型和元素个数的灵活性, 只能玩玩模板了, 看看下面:

  #include <stdio.h>

  template<typename elemType, size_t nSize>

  class CRefAsParam

  {

  public:

  typedef elemType MyArray[nSize];

  // 当然, 本函数也可以定义成形如:  static const void RefAsParam(const MyArray & aRR)

  static void RefAsParam(MyArray & aRR)

  {

  printf(“==== %d  == %d ====\r\n”, aRR[0], sizeof(aRR));

  }

  };

  void main( void )

  {

  typedef CRefAsParam<int, 10> MyType;

  MyType::MyArray a = {20, 30, 77};

  MyType::RefAsParam(a);

  }这样一来, sizeof(aRR) 值是达到 40 了, 但咱们也玩了相当的奇技淫巧. 跟我们追求的简单,直接,有效简直差了十万八千里.哎~~~

原创文章,转载请注明: 转载自日光博客

本文链接地址: C++ 的指针和引用

随机日志