函数使用结构体、结构体指针作为返回值分析
/dfq12345/article/details/73924580
使用结构体作为返回值
分析反汇编代码可知,当被调用的子函数返回值为结构体的时候,调用函数将分配一段空间用于存放返回的结构体(使用一个结构体变量接受返回值),并将这段空间的地址作为调用时的参数压栈。子程序不负责对要返回的结构体分配空间。最后返回eax中存放的是结构体空间(栈中)的地址。在子程序退出的时候,调用函数可以在自己的栈帧中访问到返回的值。
#include <stdio.h>typedef struct { int a; int b;}Stu;Stu getStu(int x, int y){ Stu result; result.a = x; result.b = y; return result;}int main(){ int a = 2, b = 3; Stu test = getStu(a, b); printf("%d %d\n", test.a, test.b); return 0;}
反汇编代码如下:
080483c4 <getStu>: 80483c4: 55 push %ebp 80483c5: 89 e5 mov %esp,%ebp 80483c7: 83 ec 10 sub $0x10,%esp 80483ca: 8b 4d 08 mov 0x8(%ebp),%ecx 80483cd: 8b 45 0c mov 0xc(%ebp),%eax 80483d0: 89 45 f8 mov %eax,-0x8(%ebp) 80483d3: 8b 45 10 mov 0x10(%ebp),%eax 80483d6: 89 45 fc mov %eax,-0x4(%ebp) 80483d9: 8b 45 f8 mov -0x8(%ebp),%eax 80483dc: 8b 55 fc mov -0x4(%ebp),%edx 80483df: 89 01 mov %eax,(%ecx) 80483e1: 89 51 04 mov %edx,0x4(%ecx) 80483e4: 89 c8 mov %ecx,%eax 80483e6: c9 leave 80483e7: c2 04 00 ret $0x4080483ea <main>: 80483ea: 8d 4c 24 04 lea 0x4(%esp),%ecx 80483ee: 83 e4 f0 and $0xfffffff0,%esp 80483f1: ff 71 fc pushl -0x4(%ecx) 80483f4: 55 push %ebp 80483f5: 89 e5 mov %esp,%ebp 80483f7: 51 push %ecx 80483f8: 83 ec 24 sub $0x24,%esp 80483fb: c7 45 f0 02 00 00 00 movl $0x2,-0x10(%ebp) 8048402: c7 45 f4 03 00 00 00 movl $0x3,-0xc(%ebp) 8048409: 8d 45 e8 lea -0x18(%ebp),%eax 804840c: 8b 55 f4 mov -0xc(%ebp),%edx 804840f: 89 54 24 08 mov %edx,0x8(%esp) 8048413: 8b 55 f0 mov -0x10(%ebp),%edx 8048416: 89 54 24 04 mov %edx,0x4(%esp) 804841a: 89 04 24 mov %eax,(%esp) 804841d: e8 a2 ff ff ff call 80483c4 <getStu> 8048422: 83 ec 04 sub $0x4,%esp 8048425: 8b 4d ec mov -0x14(%ebp),%ecx 8048428: 8b 55 e8 mov -0x18(%ebp),%edx 804842b: b8 14 85 04 08 mov $0x8048514,%eax 8048430: 89 4c 24 08 mov %ecx,0x8(%esp) 8048434: 89 54 24 04 mov %edx,0x4(%esp) 8048438: 89 04 24 mov %eax,(%esp) 804843b: e8 b4 fe ff ff call 80482f4 <printf@plt> 8048440: b8 00 00 00 00 mov $0x0,%eax 8048445: 8b 4d fc mov -0x4(%ebp),%ecx 8048448: c9 leave 8048449: 8d 61 fc lea -0x4(%ecx),%esp使用结构体指针作为返回值
在反汇编代码中可以看到,子程序填充malloc在堆中生成的结构体空间,并将其地址存放在eax中返回。但是这种使用方式存在的很大问题是在子程序中使用到了malloc但是没有与之对应的free,如果在调用函数中忽视释放操作的话将会导致堆内存的泄露。当然在C++中可以使用构造函数和析构函数处理这些细节。
测试使用的C程序:
#include <stdio.h>#include <stdlib.h>typedef struct { int a; int b;}Stu;Stu * getStu(int x, int y){ Stu *pStu = malloc(sizeof(Stu)); pStu->a = x; pStu->b = y; return pStu;}int main(){ int x = 2, y = 3; Stu *pStu = getStu(x, y); printf("%d %d\n", pStu->a, pStu->b); free(pStu); return 0;}
反汇编部分代码如下:
08048424 <getStu>: 8048424: 55 push %ebp 8048425: 89 e5 mov %esp,%ebp 8048427: 83 ec 28 sub $0x28,%esp 804842a: c7 04 24 08 00 00 00 movl $0x8,(%esp) 8048431: e8 1e ff ff ff call 8048354 <malloc@plt> 8048436: 89 45 f4 mov %eax,-0xc(%ebp) 8048439: 8b 45 f4 mov -0xc(%ebp),%eax 804843c: 8b 55 08 mov 0x8(%ebp),%edx 804843f: 89 10 mov %edx,(%eax) 8048441: 8b 45 f4 mov -0xc(%ebp),%eax 8048444: 8b 55 0c mov 0xc(%ebp),%edx 8048447: 89 50 04 mov %edx,0x4(%eax) 804844a: 8b 45 f4 mov -0xc(%ebp),%eax 804844d: c9 leave 804844e: c3 ret 0804844f <main>: 804844f: 55 push %ebp 8048450: 89 e5 mov %esp,%ebp 8048452: 83 e4 f0 and $0xfffffff0,%esp 8048455: 83 ec 20 sub $0x20,%esp 8048458: c7 44 24 14 02 00 00 movl $0x2,0x14(%esp) 804845f: 00 8048460: c7 44 24 18 03 00 00 movl $0x3,0x18(%esp) 8048467: 00 8048468: 8b 44 24 18 mov 0x18(%esp),%eax 804846c: 89 44 24 04 mov %eax,0x4(%esp) 8048470: 8b 44 24 14 mov 0x14(%esp),%eax 8048474: 89 04 24 mov %eax,(%esp) 8048477: e8 a8 ff ff ff call 8048424 <getStu> 804847c: 89 44 24 1c mov %eax,0x1c(%esp) 8048480: 8b 44 24 1c mov 0x1c(%esp),%eax 8048484: 8b 48 04 mov 0x4(%eax),%ecx 8048487: 8b 44 24 1c mov 0x1c(%esp),%eax 804848b: 8b 10 mov (%eax),%edx 804848d: b8 84 85 04 08 mov $0x8048584,%eax 8048492: 89 4c 24 08 mov %ecx,0x8(%esp) 8048496: 89 54 24 04 mov %edx,0x4(%esp) 804849a: 89 04 24 mov %eax,(%esp)