聘我网

新概念招聘3.0

C是如何返回struct的?

vote up0vote downstar

一般的简单数据类型直接在%rax中就返回了,但复杂一些的struct是如何返回的呢?

 

1 个答复

vote up0vote downcheck

如果struct不大于一个register大小,直接保存在%rax

如果struct1~2register之间,一般保存在%rax%rdx

大于2register的情况,一般是calling function传一个隐藏的指针给called function,然后后者往指针处赋值。

但这是依赖于编译器的,不同编译器实现可能不一样。

所以如果是动态链接库,是坚决不鼓励返回一个struct的。

下面看一个具体的例子:

#include<stdio.h>
typedef struct {
    long i;
    long j;
    char c;
} t_test;

t_test func()
{
    t_test t;
    t.i = 100;
    t.j = 90;
    t.c = 'a';
    return t;
}
int main(int arg, char* argv[]){
    t_test a;
    a = func();
    printf("a.i=%ld\na.j=%ld\na.c=%c\n", a.i, a.j, a.c);
    return 0;
}

先看calling function:

0x00000000004004db <main+15>:   lea    -0x20(%rbp),%rdi
0x00000000004004df <main+19>:   mov    $0x0,%eax
0x00000000004004e4 <main+24>:   callq  0x400498 <func>

果然是通过%rdi传了个隐藏的指针,指向-0x20(%rbp)

再看called function:

Dump of assembler code for function func:
0x0000000000400498 <func+0>:    push   %rbp
0x0000000000400499 <func+1>:    mov    %rsp,%rbp
0x000000000040049c <func+4>:    movq   $0x64,-0x20(%rbp)
0x00000000004004a4 <func+12>:   movq   $0x5a,-0x18(%rbp)
0x00000000004004ac <func+20>:   movb   $0x61,-0x10(%rbp)
0x00000000004004b0 <func+24>:   mov    -0x20(%rbp),%rax
0x00000000004004b4 <func+28>:   mov    %rax,(%rdi)
0x00000000004004b7 <func+31>:   mov    -0x18(%rbp),%rax
0x00000000004004bb <func+35>:   mov    %rax,0x8(%rdi)
0x00000000004004bf <func+39>:   mov    -0x10(%rbp),%rax
0x00000000004004c3 <func+43>:   mov    %rax,0x10(%rdi)
0x00000000004004c7 <func+47>:   mov    %rdi,%rax
0x00000000004004ca <func+50>:   leaveq 
0x00000000004004cb <func+51>:   retq   
End of assembler dump.

也是一致的,先把struct拷贝到%rdi指向的内存区域,再把%rdi赋值给%rax

在动态库中直接返回struct要尽量避免:)

注意

指令集(Instruction Set Architecture)对内存的读、写总是指定的单元的低地址(上升地址),e.g. mov %rax,0x10(%rdi)操作的内存范围是0x10(%rdi)~0x18(%rdi)

链接

您的回答





不是您要找的问题? 浏览其他含有标签 的问题或者 自己问个.