老钟古

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

今天,在看《Effective C++》书籍的时候,看到const的在作为函数参数传递时的应用,一般函数参数的传递有三种方式,passed by pointer-to-constpassed by reference-to-constpassed by value,相信对这三种方式都应该比较熟悉,普通的内置类型三者的效率都差不多,但对于用户自定义的类型,比如structclass这些,使用前两种的效率就要高一些了。还有就是前两种的使用是改变实参本身的值,而后一种则只是改变实参副本的值,对实参本身并没有改变。下面举一个简单的交换两个数的函数,我想通过这个例子应该能够说明问题。

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4  
 5 void SwapValue(int a, int b)
 6 {
 7        int temp = 0;
 8        temp = a;
 9        a = b;
10        b = temp;
11 }
12  
13 void SwapPointer(int *a, int *b)
14 {
15        int temp = 0;
16        temp = *a;
17        *= *b;
18        *= temp;
19 }
20  
21 void SwapReference(int& a, int &b)
22 {
23        int temp = 0;
24        temp = a;
25        a = b;
26        b = temp;
27 }
28  
29 int main()
30 {
31        int n = 5, m = 6;
32        SwapValue(n, m);
33        printf("%d %d\n", n, m);
34  
35        SwapPointer(&n, &m);
36        printf("%d %d\n", n, m);
37  
38        SwapReference(n, m);
39        printf("%d %d\n", n, m);
40  
41        return 0;
42 }
43  

VC编译之后在调试中查看其反汇编后的内容,只列出相关的代码。

这里说明一下,对于参数和局部变量来说,一般是通过EBP寄存器来进行访问的。而且参数一般是EBP+x的形式,而局部变量一般是EBP – x的形式。

 

116:      int n = 5, m = 6;

00401158 C7 45 FC 05 00 00 00   mov         dword ptr [ebp-4],5

0040115F C7 45 F8 06 00 00 00       mov         dword ptr [ebp-8],6

这两条汇编指令是对main函数内的局部变量nm进行初始化操作

 

117:      SwapValue(n, m);

00401166 8B 45 F8             mov         eax,dword ptr [ebp-8]

00401169 50                  push        eax

0040116A 8B 4D FC             mov         ecx,dword ptr [ebp-4]

0040116D 51                       push        ecx

0040116E E8 AB FE FF FF      call        @ILT+25(SwapValue) (0040101e)

00401173 83 C4 08             add         esp,8

从上面的反汇编代码可以看出,如果参数使用的是passed by value的形式,参数的内容是先放进去寄存器中,而在函数内部改变的仅仅是寄存器的值,即是参数副本的值,对参数本身并没有改变。

 

120:      SwapPointer(&n, &m);

0040118B 8D 4D F8             lea         ecx,[ebp-8]

0040118E 51                       push        ecx

0040118F 8D 55 FC             lea         edx,[ebp-4]

00401192 52                       push        edx

00401193 E8 81 FE FF FF    call        @ILT+20(SwapPointer) (00401019)

00401198 83 C4 08               add         esp,8

这段代码是把参数的地址压入栈中,此时改变地址的内容也就是改变参数的值了。

 

123:      SwapReference(n, m);

004011B0 8D 55 F8                 lea         edx,[ebp-8]

004011B3 52                           push        edx

004011B4 8D 45 FC                lea         eax,[ebp-4]

004011B7 50                           push        eax

004011B8 E8 48 FE FF FF     call      @ILT+0(SwapReference) (00401005)

004011BD 83 C4 08                add         esp,8

这段代码跟上一段是相同的。可以看出两者都是将参数的地址压入栈中,即在函数内部改变了参数的值。

SwapValue函数

92:       int temp = 0;

00401068 C7 45 FC 00 00 00 00     mov         dword ptr [ebp-4],0

93:       temp = a;

0040106F 8B 45 08                        mov         eax,dword ptr [ebp+8]

00401072 89 45 FC                        mov         dword ptr [ebp-4],eax

94:       a = b;

00401075 8B 4D 0C                  mov         ecx,dword ptr [ebp+0Ch]

00401078 89 4D 08                  mov         dword ptr [ebp+8],ecx

95:       b = temp;

0040107B 8B 55 FC                      mov         edx,dword ptr [ebp-4]

0040107E 89 55 0C                       mov         dword ptr [ebp+0Ch],edx

96:   }

 

SwapPointer函数

100:      int temp = 0;

004010B8 C7 45 FC 00 00 00 00    mov         dword ptr [ebp-4],0

101:      temp = *a;

004010BF 8B 45 08                        mov         eax,dword ptr [ebp+8]

004010C2 8B 08                        mov         ecx,dword ptr [eax]

004010C4 89 4D FC                 mov         dword ptr [ebp-4],ecx

102:      *a = *b;

004010C7 8B 55 08                 mov         edx,dword ptr [ebp+8]

004010CA 8B 45 0C                    mov         eax,dword ptr [ebp+0Ch]

004010CD 8B 08                   mov         ecx,dword ptr [eax]

004010CF 89 0A                   mov         dword ptr [edx],ecx

103:      *b = temp;

004010D1 8B 55 0C                    mov         edx,dword ptr [ebp+0Ch]

004010D4 8B 45 FC                    mov         eax,dword ptr [ebp-4]

004010D7 89 02                          mov         dword ptr [edx],eax

104: }

 

SwapReference函数

108:      int temp = 0;

00401108 C7 45 FC 00 00 00 00     mov         dword ptr [ebp-4],0

109:      temp = a;

0040110F 8B 45 08                  mov         eax,dword ptr [ebp+8]

00401112 8B 08                             mov         ecx,dword ptr [eax]

00401114 89 4D FC                  mov         dword ptr [ebp-4],ecx

110:      a = b;

00401117 8B 55 08                  mov         edx,dword ptr [ebp+8]

0040111A 8B 45 0C                  mov         eax,dword ptr [ebp+0Ch]

0040111D 8B 08                     mov         ecx,dword ptr [eax]

0040111F 89 0A                     mov         dword ptr [edx],ecx

111:      b = temp;

00401121 8B 55 0C                  mov         edx,dword ptr [ebp+0Ch]

00401124 8B 45 FC                  mov         eax,dword ptr [ebp-4]

00401127 89 02                      mov         dword ptr [edx],eax

112: }

参数使用passed by pointerpassed by reference两者反汇编出来的代码是一样的,且传给函数的是参数本身的地址。所以对地址内容的改变也就是对参数的改变。

posted on 2011-03-12 16:49  老钟古  阅读(474)  评论(0编辑  收藏  举报