C++中函数中参数和返回值都是用户定义类型(这里主要是类的情况时的分析)

来源:互联网 发布:一诺网络诈骗 编辑:程序博客网 时间:2024/04/29 16:08
以下这个程序中使用了参数传值和返回值传值的操作:
class A
{
public:
    A()
    {
        i = 0;
    }

    A(const A& c)
    {
       i = c.i;
    }
private:
    int i;
};


A funbyValue(A c)
{
    return c;
}

void main(int argc,char* argv[])
{
   A b;
   funbyValue(b);
}

该程序相应的汇编代码如下(环境使用vs2003, windows系统):
; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.3077

    TITLE    ./main.cpp
    .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
_DATA    SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA    ENDS
CONST    SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST    ENDS
_BSS    SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS    ENDS
$$SYMBOLS    SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS    ENDS
$$TYPES    SEGMENT BYTE USE32 'DEBTYP'
$$TYPES    ENDS
_TLS    SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS    ENDS
;    COMDAT ??0A@@QAE@XZ
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ??0A@@QAE@ABV0@@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT ?funbyValue@@YA?AVA@@V1@@Z
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
;    COMDAT _main
_TEXT    SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT    ENDS
sxdata    SEGMENT DWORD USE32 'SXDATA'
sxdata    ENDS
FLAT    GROUP _DATA, CONST, _BSS
    ASSUME    CS: FLAT, DS: FLAT, SS: FLAT
endif

INCLUDELIB LIBCD
INCLUDELIB OLDNAMES

PUBLIC    ??0A@@QAE@ABV0@@Z                ; A::A
PUBLIC    ?funbyValue@@YA?AVA@@V1@@Z            ; funbyValue
EXTRN    __RTC_InitBase:NEAR
EXTRN    __RTC_Shutdown:NEAR
EXTRN    __RTC_CheckEsp:NEAR
;    COMDAT rtc$IMZ
; File j:/example/contructor/main.cpp
rtc$IMZ    SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
rtc$IMZ    ENDS
;    COMDAT rtc$TMZ
rtc$TMZ    SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
; Function compile flags: /Odt /RTCsu /ZI
rtc$TMZ    ENDS
;    COMDAT ?funbyValue@@YA?AVA@@V1@@Z
_TEXT    SEGMENT
___$ReturnUdt$ = 8                    ; size = 4
_c$ = 12                        ; size = 4
?funbyValue@@YA?AVA@@V1@@Z PROC NEAR            ; funbyValue, COMDAT

; 19   : {

  00000    55         push     ebp
  00001    8b ec         mov     ebp, esp
  00003    81 ec c0 00 00
    00         sub     esp, 192        ; 000000c0H
  00009    53         push     ebx
  0000a    56         push     esi
  0000b    57         push     edi
  0000c    8d bd 40 ff ff
    ff         lea     edi, DWORD PTR [ebp-192]
  00012    b9 30 00 00 00     mov     ecx, 48            ; 00000030H
  00017    b8 cc cc cc cc     mov     eax, -858993460        ; ccccccccH
  0001c    f3 ab         rep stosd

; 20   :     return c;

  0001e    8d 45 0c     lea     eax, DWORD PTR _c$[ebp]
  00021    50         push     eax
  00022    8b 4d 08     mov     ecx, DWORD PTR ___$ReturnUdt$[ebp]
  00025    e8 00 00 00 00     call     ??0A@@QAE@ABV0@@Z    ; A::A
  0002a    8b 45 08     mov     eax, DWORD PTR ___$ReturnUdt$[ebp]

; 21   : }

  0002d    5f         pop     edi
  0002e    5e         pop     esi
  0002f    5b         pop     ebx
  00030    81 c4 c0 00 00
    00         add     esp, 192        ; 000000c0H
  00036    3b ec         cmp     ebp, esp
  00038    e8 00 00 00 00     call     __RTC_CheckEsp
  0003d    8b e5         mov     esp, ebp
  0003f    5d         pop     ebp
  00040    c3         ret     0
?funbyValue@@YA?AVA@@V1@@Z ENDP                ; funbyValue
; Function compile flags: /Odt /RTCsu /ZI
_TEXT    ENDS
;    COMDAT ??0A@@QAE@ABV0@@Z
_TEXT    SEGMENT
_this$ = -8                        ; size = 4
_c$ = 8                            ; size = 4
??0A@@QAE@ABV0@@Z PROC NEAR                ; A::A, COMDAT
; _this$ = ecx

; 9    :     A(const A& c)

  00000    55         push     ebp
  00001    8b ec         mov     ebp, esp
  00003    81 ec cc 00 00
    00         sub     esp, 204        ; 000000ccH
  00009    53         push     ebx
  0000a    56         push     esi
  0000b    57         push     edi
  0000c    51         push     ecx
  0000d    8d bd 34 ff ff
    ff         lea     edi, DWORD PTR [ebp-204]
  00013    b9 33 00 00 00     mov     ecx, 51            ; 00000033H
  00018    b8 cc cc cc cc     mov     eax, -858993460        ; ccccccccH
  0001d    f3 ab         rep stosd
  0001f    59         pop     ecx
  00020    89 4d f8     mov     DWORD PTR _this$[ebp], ecx

; 10   :     {
; 11   :        i = c.i;

  00023    8b 45 f8     mov     eax, DWORD PTR _this$[ebp]
  00026    8b 4d 08     mov     ecx, DWORD PTR _c$[ebp]
  00029    8b 11         mov     edx, DWORD PTR [ecx]
  0002b    89 10         mov     DWORD PTR [eax], edx

; 12   :     }

  0002d    8b 45 f8     mov     eax, DWORD PTR _this$[ebp]
  00030    5f         pop     edi
  00031    5e         pop     esi
  00032    5b         pop     ebx
  00033    8b e5         mov     esp, ebp
  00035    5d         pop     ebp
  00036    c2 04 00     ret     4
??0A@@QAE@ABV0@@Z ENDP                    ; A::A
_TEXT    ENDS
PUBLIC    ??0A@@QAE@XZ                    ; A::A
PUBLIC    _main
EXTRN    @_RTC_CheckStackVars@8:NEAR
; Function compile flags: /Odt /RTCsu /ZI
;    COMDAT _main
_TEXT    SEGMENT
$T315 = -212                        ; size = 4
_b$ = -8                        ; size = 4
_argc$ = 8                        ; size = 4
_argv$ = 12                        ; size = 4
_main    PROC NEAR                    ; COMDAT

; 24   : {

  00000    55         push     ebp
  00001    8b ec         mov     ebp, esp
  00003    81 ec e4 00 00
    00         sub     esp, 228        ; 000000e4H
  00009    53         push     ebx
  0000a    56         push     esi
  0000b    57         push     edi
  0000c    8d bd 1c ff ff
    ff         lea     edi, DWORD PTR [ebp-228]
  00012    b9 39 00 00 00     mov     ecx, 57            ; 00000039H
  00017    b8 cc cc cc cc     mov     eax, -858993460        ; ccccccccH
  0001c    f3 ab         rep stosd

; 25   :    A b;

  0001e    8d 4d f8     lea     ecx, DWORD PTR _b$[ebp]
  00021    e8 00 00 00 00     call     ??0A@@QAE@XZ        ; A::A

; 26   :    funbyValue(b);

  00026    51         push     ecx
  00027    8b cc         mov     ecx, esp
  00029    8d 45 f8     lea     eax, DWORD PTR _b$[ebp]
  0002c    50         push     eax
  0002d    e8 00 00 00 00     call     ??0A@@QAE@ABV0@@Z    ; A::A
  00032    8d 8d 2c ff ff
    ff         lea     ecx, DWORD PTR $T315[ebp]
  00038    51         push     ecx
  00039    e8 00 00 00 00     call     ?funbyValue@@YA?AVA@@V1@@Z ; funbyValue
  0003e    83 c4 08     add     esp, 8

; 27   : }

  00041    33 c0         xor     eax, eax
  00043    52         push     edx
  00044    8b cd         mov     ecx, ebp
  00046    50         push     eax
  00047    8d 15 00 00 00
    00         lea     edx, DWORD PTR $L318
  0004d    e8 00 00 00 00     call     @_RTC_CheckStackVars@8
  00052    58         pop     eax
  00053    5a         pop     edx
  00054    5f         pop     edi
  00055    5e         pop     esi
  00056    5b         pop     ebx
  00057    81 c4 e4 00 00
    00         add     esp, 228        ; 000000e4H
  0005d    3b ec         cmp     ebp, esp
  0005f    e8 00 00 00 00     call     __RTC_CheckEsp
  00064    8b e5         mov     esp, ebp
  00066    5d         pop     ebp
  00067    c3         ret     0
$L318:
  00068    01 00 00 00     DD     1
  0006c    00 00 00 00     DD     $L317
$L317:
  00070    f8 ff ff ff     DD     -8            ; fffffff8H
  00074    04 00 00 00     DD     4
  00078    00 00 00 00     DD     $L316
$L316:
  0007c    62         DB     98            ; 00000062H
  0007d    00         DB     0
_main    ENDP
; Function compile flags: /Odt /RTCsu /ZI
_TEXT    ENDS
;    COMDAT ??0A@@QAE@XZ
_TEXT    SEGMENT
_this$ = -8                        ; size = 4
??0A@@QAE@XZ PROC NEAR                    ; A::A, COMDAT
; _this$ = ecx

; 4    :     A()

  00000    55         push     ebp
  00001    8b ec         mov     ebp, esp
  00003    81 ec cc 00 00
    00         sub     esp, 204        ; 000000ccH
  00009    53         push     ebx
  0000a    56         push     esi
  0000b    57         push     edi
  0000c    51         push     ecx
  0000d    8d bd 34 ff ff
    ff         lea     edi, DWORD PTR [ebp-204]
  00013    b9 33 00 00 00     mov     ecx, 51            ; 00000033H
  00018    b8 cc cc cc cc     mov     eax, -858993460        ; ccccccccH
  0001d    f3 ab         rep stosd
  0001f    59         pop     ecx
  00020    89 4d f8     mov     DWORD PTR _this$[ebp], ecx

; 5    :     {
; 6    :         i = 0;

  00023    8b 45 f8     mov     eax, DWORD PTR _this$[ebp]
  00026    c7 00 00 00 00
    00         mov     DWORD PTR [eax], 0

; 7    :     }

  0002c    8b 45 f8     mov     eax, DWORD PTR _this$[ebp]
  0002f    5f         pop     edi
  00030    5e         pop     esi
  00031    5b         pop     ebx
  00032    8b e5         mov     esp, ebp
  00034    5d         pop     ebp
  00035    c3         ret     0
??0A@@QAE@XZ ENDP                    ; A::A
_TEXT    ENDS
END


总结:从程序相应的汇编中我们可以看到 funbyValue中参数和返回值的内存都是分配在调用函数中:
分析:由粗线部分我们可以知道类对象的this指针地址值放到寄存器ecx中,在类对象的方法中我们可以看到ecx中的地址值被复制到方法的堆栈中,然后对this指向对象中其他成员的方法。
由红色粗斜线部分我们可以知道类对象的成员方法中,参数是用户定义类型并且是传递引用的情况下,是通过压栈的方法传入的。
    在函数参数和返回值都是用户自定义的类型时,并且是传值的情况下,他们都是在调用者的空间中进行分配的:(1)对于参数则是在栈顶分配的,理由是它将esp作为this指针,并且通过拷贝构造函数,将实参数的值拷贝到形参中,这可以由兰粗部分的汇编代码看出。(2)而对于返回值它是调用者的堆栈内部进行分配的,并且通过压栈的方式进入到堆栈中,这可以由粉红部分得知。

这里还有一个规律:那就是每个函数内部都是用ebp来表示它可用堆栈内存的起始部分,esp减去一定的空间,这样,esp是那个函数可以分配局部变量的堆栈的末尾。



C++中的参数和返回值的类型的选择:
(1)引用参数
(2)指针参数
(3)值类型参数

对于数据类型来说,他就是指针类型参数。
原创粉丝点击