1 函数返回值为结构体类型

前一篇文章我们学习了当函数的返回值是整形时,函数返回时,如何将返回值传递给调用者。是通过eax寄存器来传递的。

但是当返回值为结构体时,eax寄存器显然存不下结构体。那么该如何将返回值传递给调用者呢?

  • 函数调用时,用来接收函数返回值的结构体变量的地址需要入栈。
  • 然后被调用函数直接通过该结构体变量的地址,将返回值拷贝过去

但是有一点要注意,就是函数返回值用于初始化以及用于赋值时,这两个过程,内部的调用约定是不一样的。参考下面。

1.1 函数返回值用于初始化变量

上述图示的过程还是很简单的,当函数返回值作为其他变量的初始值的时候:

  • 首先将变量的地址入栈
  • 当函数返回时,将返回值拷贝到变量st的地址处即可

1.2 函数返回值给变量赋值

上述图示与11节内容不太一样。当函数返回值是给一个 变量赋值而不是初始化 的时候:

  • 首先生成一个临时的变量temp,将temp地址入栈
  • 然后当函数返回时,将返回值拷贝到这个临时变量的地址处
  • 最后再将临时变量的值赋值给st

可以看到,当函数返回值作为其他变量的 初始值 时只需要一次的数据拷贝,但是当函数返回值给其他变量 赋值时 ,却是两次的数据拷贝。所以在平时的代码中,尽量都是直接将函数返回值作为初始值,而尽量不要将返回值以赋值的形式给其他变量以免造成不必要的开销。

2 代码案例分析

本来是想将实验过程写清楚的,但是想想,这个代码的调试过程还是留给读者吧。毕竟我前面写的二十几篇都是将完整的步骤写出来了,如果学会了前面gdb调试的内容那么自己调试应该不在话下。我只给出调试的思路和代码。

return.c

#include <stdio.h>
struct ST
    int x;
    int y;
    int z;
struct ST f(int x, int y, int z)
    struct ST st = {0};
    printf("f() : &st = %p\n", &st);
    st.x = x;
    st.y = y;
    st.z = z;
    return st;
void g()
    struct ST st = {0};
    printf("g() : &st = %p\n", &st);
    st = f(1, 2, 3);
    printf("g() : st.x = %d\n", st.x);
    printf("g() : st.y = %d\n", st.y);
    printf("g() : st.z = %d\n", st.z);
void h()
    struct ST st = f(4, 5, 6);
    printf("h() : &st = %p\n", &st);
    printf("h() : st.x = %d\n", st.x);
    printf("h() : st.y = %d\n", st.y);
    printf("h() : st.z = %d\n", st.z);
int main()
    h();
    g();
    return 0;

调试思路:使用gdb进行调试。在不同的函数栈帧中查看当前函数栈帧中,结构体变量的地址是否入栈或者是否有一个临时变量的地址入栈。然后通过使用gdb打断点的形式,证明最终函数返回时是将返回值拷贝到相应的地址。当然,最后最干脆的方法还是查看该程序的反汇编代码,通过阅读反汇编代码来更加清晰的认识整个函数的运行机制。

好了,这次就不写调试步骤了,有心的人可以自己调试哦~

  • 函数返回值为结构体的时候,如何将返回值传递给调用者
  • 函数返回值作为初始化与赋值时的不同。注意效率问题
上一篇文章学习了几种函数调用约定的区别,点击链接查看上一篇文章:【软件开发底层知识修炼】二十四 ABI之函数调用约定本篇文章继续学习函数调用约定中,关于函数返回值的问题。当函数返回值为结构体时,函数返回值是如何来传给调用者的。文章目录1 函数返回值为结构体类型1.1 函数返回值用于初始化变量1.2 函数返回值给变量赋值2 代码案例分析3 总结1 函数返回值为结构体类型前一篇文章...
春招结束,发现面试的后面几面,会闻到c++的abi问题,大致问题就是,gcc编译的库,clang能用吗,或者在升级so文件的候要注意什么,当不知道,现在来总结一下。 这个abi问题,网上资料不是很多,有一些零零散散的,最后自己总结了一下以后,在这里做个笔记。 一般的软件为了模块分割,思路都是这样的: 模块写在so/dll文件中,使用exe加载并执行功能,更新只用更新dll、so就可以了。...
C++ ABI探究和兼容性问题 ABI(Application Binary Interface) 应用程序进制接口,描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口。 编程语言实现的 ABI 是一种可以使单独编译的模块协同工作的低级细节的规范。如果没有一个稳定的 ABI,就必须使用同一编译器的同一版本编译程序的所有部分。 C ABI Oracle Solari...
上一篇文章学习了Linux环境下的函数栈帧的形成与摧毁。点击链接查看相关文章:软件开发底层知识修炼十三 ABI-应用程序进制接口三之深入理解函数栈帧的形成与摧毁 本篇文章继续学习ABI接口相关的内容。函数调用约定 文章目录1 函数参数如何入栈,返回值在哪里2 函数调用约定的编程实验2.1 使用gdb调试代码证明eax存的值是函数返回值2 .2 查看程序的反汇编文件来说明调用约定的不...
刚参加工作,总是听到PM分配任务的候提到打桩的概念。查看项目代码的候又碰到打桩函数中的HOOK技术。对于这两种技术我以前都没有接触过,在网上查了下资料,备份如下,希望对自己和他人都能有所帮助。 在软件测试的候经常需要动态的替换被测函数调用的其它函数,而这个替换就叫做打桩。比如现在要测试函数A,但是函数A调用了还没有实现的函数B,那么我们给函数B创造打桩函数STUB_B,STUB_B可