以下这个程序中使用了参数传值和返回值传值的操作classA{public:A(){i0;}A(constA}private:inti;} 以下这个程序中使用了参数传值和返回值传值的操作class A{public: A() { i 0;
以下这个程序中使用了参数传值和返回值传值的操作classA{public:A(){i0;}A(constA}private:inti;} 以下这个程序中使用了参数传值和返回值传值的操作class A{public: A() { i 0; } A(const A 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 .386Pinclude listing.incif Version gt 510.model FLATelse_TEXT SEGMENT PARA USE32 PUBLIC CODE_TEXT ENDS_DATA SEGMENT DWORD USE32 PUBLIC DATA_DATA ENDSCONST SEGMENT DWORD USE32 PUBLIC CONSTCONST 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 ??0AQAEXZ_TEXT SEGMENT PARA USE32 PUBLIC CODE_TEXT ENDS; COMDAT ??0AQAEABV0Z_TEXT SEGMENT PARA USE32 PUBLIC CODE_TEXT ENDS; COMDAT ?funbyValueYA?AVAV1Z_TEXT SEGMENT PARA USE32 PUBLIC CODE_TEXT ENDS; COMDAT _main_TEXT SEGMENT PARA USE32 PUBLIC CODE_TEXT ENDSsxdata SEGMENT DWORD USE32 SXDATAsxdata ENDSFLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLATendifINCLUDELIB LIBCDINCLUDELIB OLDNAMESPUBLIC ??0AQAEABV0Z ; A::APUBLIC ?funbyValueYA?AVAV1Z ; funbyValueEXTRN __RTC_InitBase:NEAREXTRN __RTC_Shutdown:NEAREXTRN __RTC_CheckEsp:NEAR; COMDAT rtc$IMZ; File j:/example/contructor/main.cpprtc$IMZ SEGMENT__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBasertc$IMZ ENDS; COMDAT rtc$TMZrtc$TMZ SEGMENT__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown; Function compile flags: /Odt /RTCsu /ZIrtc$TMZ ENDS; COMDAT ?funbyValueYA?AVAV1Z_TEXT SEGMENT___$ReturnUdt$ 8 ; size 4_c$ 12 ; size 4?funbyValueYA?AVAV1Z 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 ??0AQAEABV0Z ; 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?funbyValueYA?AVAV1Z ENDP ; funbyValue; Function compile flags: /Odt /RTCsu /ZI_TEXT ENDS; COMDAT ??0AQAEABV0Z_TEXT SEGMENT_this$ -8 ; size 4_c$ 8 ; size 4??0AQAEABV0Z PROC NEAR ; A::A, COMDAT; _this$ ecx; 9 : A(const A 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??0AQAEABV0Z ENDP ; A::A_TEXT ENDSPUBLIC ??0AQAEXZ ; A::APUBLIC _mainEXTRN _RTC_CheckStackVars8: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 ??0AQAEXZ ; 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 ??0AQAEABV0Z ; 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 ?funbyValueYA?AVAV1Z ; 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_CheckStackVars8 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 ??0AQAEXZ_TEXT SEGMENT_this$ -8 ; size 4??0AQAEXZ 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??0AQAEXZ ENDP ; A::A_TEXT ENDSEND总结从程序相应的汇编中我们可以看到 funbyValue中参数和返回值的内存都是分配在调用函数中分析由粗线部分我们可以知道类对象的this指针地址值放到寄存器ecx中在类对象的方法中我们可以看到ecx中的地址值被复制到方法的堆栈中然后对this指向对象中其他成员的方法。由红色粗斜线部分我们可以知道类对象的成员方法中参数是用户定义类型并且是传递引用的情况下是通过压栈的方法传入的。 在函数参数和返回值都是用户自定义的类型时并且是传值的情况下他们都是在调用者的空间中进行分配的1对于参数则是在栈顶分配的理由是它将esp作为this指针并且通过拷贝构造函数将实参数的值拷贝到形参中这可以由兰粗部分的汇编代码看出。2而对于返回值它是调用者的堆栈内部进行分配的并且通过压栈的方式进入到堆栈中这可以由粉红部分得知。这里还有一个规律那就是每个函数内部都是用ebp来表示它可用堆栈内存的起始部分esp减去一定的空间这样esp是那个函数可以分配局部变量的堆栈的末尾。C中的参数和返回值的类型的选择引用参数指针参数值类型参数对于数据类型来说他就是指针类型参数。