1. 程式人生 > >【C/C++開發】函式使用結構體、結構體指標作為返回值分析

【C/C++開發】函式使用結構體、結構體指標作為返回值分析

函式使用結構體、結構體指標作為返回值分析

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)