百度电话人工服务,站长工具的使用seo综合查询排名,会员卡管理系统哪里买,photoshop touch上一篇文章学习了几种函数调用约定的区别#xff0c;点击链接查看上一篇文章#xff1a;【软件开发底层知识修炼】二十四 ABI之函数调用约定本篇文章继续学习函数调用约定中#xff0c;关于函数返回值的问题。当函数返回值为结构体时#xff0c;函数返回值是如何来传给调用… 上一篇文章学习了几种函数调用约定的区别点击链接查看上一篇文章【软件开发底层知识修炼】二十四 ABI之函数调用约定本篇文章继续学习函数调用约定中关于函数返回值的问题。当函数返回值为结构体时函数返回值是如何来传给调用者的。 文章目录1 函数返回值为结构体类型1.1 函数返回值用于初始化变量1.2 函数返回值给变量赋值2 代码案例分析3 总结 1 函数返回值为结构体类型
前一篇文章我们学习了当函数的返回值是整形时函数返回时如何将返回值传递给调用者。是通过eax寄存器来传递的。
但是当返回值为结构体时eax寄存器显然存不下结构体。那么该如何将返回值传递给调用者呢
函数调用时用来接收函数返回值的结构体变量的地址需要入栈。然后被调用函数直接通过该结构体变量的地址将返回值拷贝过去 但是有一点要注意就是函数返回值用于初始化以及用于赋值时这两个过程内部的调用约定是不一样的。参考下面。 1.1 函数返回值用于初始化变量 上述图示的过程还是很简单的当函数返回值作为其他变量的初始值的时候 首先将变量的地址入栈当函数返回时将返回值拷贝到变量st的地址处即可 1.2 函数返回值给变量赋值 上述图示与11节内容不太一样。当函数返回值是给一个变量赋值而不是初始化的时候 首先生成一个临时的变量temp将temp地址入栈然后当函数返回时将返回值拷贝到这个临时变量的地址处最后再将临时变量的值赋值给st 可以看到当函数返回值作为其他变量的初始值时只需要一次的数据拷贝但是当函数返回值给其他变量赋值时却是两次的数据拷贝。所以在平时的代码中尽量都是直接将函数返回值作为初始值而尽量不要将返回值以赋值的形式给其他变量以免造成不必要的开销。
2 代码案例分析
本来是想将实验过程写清楚的但是想想这个代码的调试过程还是留给读者吧。毕竟我前面写的二十几篇都是将完整的步骤写出来了如果学会了前面gdb调试的内容那么自己调试应该不在话下。我只给出调试的思路和代码。
代码
return.c
#include stdio.hstruct 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打断点的形式证明最终函数返回时是将返回值拷贝到相应的地址。当然最后最干脆的方法还是查看该程序的反汇编代码通过阅读反汇编代码来更加清晰的认识整个函数的运行机制。
好了这次就不写调试步骤了有心的人可以自己调试哦~
3 总结
学会了
函数返回值为结构体的时候如何将返回值传递给调用者函数返回值作为初始化与赋值时的不同。注意效率问题