【C/C++開發】函式使用結構體、結構體指標作為返回值分析
阿新 • • 發佈:2018-10-31
函式使用結構體、結構體指標作為返回值分析
32位機,gcc編譯器
使用結構體作為返回值
分析反彙編程式碼可知,當被呼叫的子函式返回值為結構體的時候,呼叫函式將分配一段空間用於存放返回的結構體(使用一個結構體變數接受返回值),並將這段空間的地址作為呼叫時的引數壓棧。子程式不負責對要返回的結構體分配空間。最後返回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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
反彙編程式碼如下:
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
80483 cd: 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 $0x4
080483ea <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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
使用結構體指標作為返回值
在反彙編程式碼中可以看到,子程式填充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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
反彙編部分程式碼如下:
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)