广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C/C++函数原理传参示例详解
  • 208
分享到

C/C++函数原理传参示例详解

C/C++函数原理传参C/C++函数传参 2022-12-08 20:12:57 208人浏览 八月长安
摘要

目录x84-64的寄存器函数是个什么东西?一个简单的函数传参姿势入栈规则看看汇编全都存寄存器吗?传对象呢?x84-64的寄存器 本文所用GCc为 x86-64 gcc 10.1 w

x84-64的寄存器

本文所用GCcx86-64 gcc 10.1

wiki.cdot.senecacollege.ca/wiki/X86_64…

rax - reGISter a extended

rbx - register b extended

rcx - register c extended

rdx - register d extended

rbp - register base pointer (start of stack)

rsp - register stack pointer (current location in stack, growing downwards)

rsi - register source index (source for data copies)

rdi - register destination index (destination for data copies)

其他寄存器: r8 r9 r10 r11 r12 r13 r14 r15

函数是个什么东西?

一个简单的函数

int func(){}
int main() {
    int x = 2;
    func();
}
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    $2, -4(%rbp)
        call    func()
        movl    $0, %eax
        leave
        ret

分配空间动作如下所示:

这里加了个函数调用是因为在有些时候,没有函数调用,就不会使用subq $16, %rsp 这一条指令,我的猜想是既然你都是栈顶的,并且不会再有rbp的变化,那么栈顶以上的元素我都可以随便用。
并且我们观察可以得知,分配栈空间时,他是分配的16个字节,也就是说,有对齐
返回时,弹出栈顶,就可以恢复到上一个栈帧的状态了。

传参姿势

入栈规则

C/C++ 中规定的函数压栈顺序是从右到左,当然,如果你是 Visual C/c++的话,它们有更多的玩法 比如:

template<typename T>
T val(T t) {
  cout << t << endl;
  return t;
}
signed main() {
  printf("%d%d%d", val(1), val(2), val(3));
  return 0;
}

结果

3
2
1
123

看看汇编

int func(int x, int y, int z) {
  return 0;
}
int main() {
  func(1, 2, 3);
}

生成的汇编

func(int, int, int):
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        movl    %edx, -12(%rbp)
        movl    $0, %eax
        popq    %rbp
        ret
main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $3, %edx
        movl    $2, %esi
        movl    $1, %edi
        call    func(int, int, int)
        movl    $0, %eax
        popq    %rbp
        ret

上文中可以看出,也证实了我们所观察到的,首先把3传给了edx,2传给了esi,1传给了edi

全都存寄存器吗?

寄存器毕竟少,当然,还可以存在栈上嘛

int fun() {return 0;}
int func(int x, int y, int z, int a, int b, int c, int d, int e, int f){
    fun();
    return e;
}
int main() {
    func(1, 2, 3, 4, 5, 6, 7, 8, 9);
    return 0;
}
fun():
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $0, %eax
        popq    %rbp
        ret
func(int, int, int, int, int, int, int, int, int):
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $24, %rsp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        movl    %edx, -12(%rbp)
        movl    %ecx, -16(%rbp)
        movl    %r8d, -20(%rbp)
        movl    %r9d, -24(%rbp)
        call    fun()
        movl    24(%rbp), %eax
        leave
        ret
main:
        pushq   %rbp
        movq    %rsp, %rbp
        pushq   $9  // 24+%rbp
        pushq   $8  // 16+%rbp
        pushq   $7  // 8 +%rbp
        movl    $6, %r9d
        movl    $5, %r8d
        movl    $4, %ecx
        movl    $3, %edx
        movl    $2, %esi
        movl    $1, %edi
        call    func(int, int, int, int, int, int, int, int, int)
        addq    $24, %rsp
        movl    $0, %eax
        leave
        ret

主函数中的这三条语句

pushq   $9
pushq   $8
pushq   $7

说明了,当函数入栈放寄存器放不下时,会放在栈上,放在栈顶之上,等函数调用执行完成后,rbp取出回到当前位置之后,再去addq $24, %rsp 把栈弹出这些元素。

并且func函数中的movl 24(%rbp), %eax也证明了,传的参数是在栈顶的上面(自上向下增长) 24 + %rbp 刚好是 $9, 也就是局部变量f的位置

传对象呢?

在这里,暂且不谈内存布局,把一个对象看成一块内存对于的位置
这里用一个结构体做示例

struct E {int x, y, z;};
E func(E e){
    e.x = 2;
    return e;
}
int main() {
    E e = {.x = 1, .y = 2, .z = 3};
    e = func(e);
    return 0;
}
func(E):
        pushq   %rbp
        movq    %rsp, %rbp
        // 将rdi 和 esi 取出来 放到 rdx 和 eax 中
        movq    %rdi, %rdx
        movl    %esi, %eax
        // 存放到开辟好的空间中 {x = rbp - 32, y = rbp - 28, z = rbp - 24}
        movq    %rdx, -32(%rbp)
        movl    %eax, -24(%rbp)
        // 更改 x
        movl    $2, -32(%rbp)
        // 将值移动到寄存器上,从返回寄存器上移动到局部返回出去的变量
        movq    -32(%rbp), %rax
        movq    %rax, -12(%rbp)
        movl    -24(%rbp), %eax
        movl    %eax, -4(%rbp)
        // 将返回值值移动到寄存器上 rax rdx 上
        movq    -12(%rbp), %rax
        movl    -4(%rbp), %ecx
        movq    %rcx, %rdx
        popq    %rbp
        ret
main:
        // 压栈保存现场 没什么好说的
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        // 内存布局
        rbp
        | z  rbp - 4  
        | y  rbp - 8
        | x  rbp - 12
        movl    $1, -12(%rbp)
        movl    $2, -8(%rbp)
        movl    $3, -4(%rbp)
        // 移动 x 和 y 到 rdx 寄存器中
        movq    -12(%rbp), %rdx
        // 移动 z 到 eax中
        movl    -4(%rbp), %eax
        // 再将 rdx 和 eax 分别移动到rdi 和 esi中
        movq    %rdx, %rdi
        movl    %eax, %esi
        call    func(E)
        // 从rax 中取出x y
        movq    %rax, -12(%rbp)
        // 从rdx中取出z
        movl    -4(%rbp), %eax
        andl    $0, %eax
        orl     %edx, %eax //
        movl    %eax, -4(%rbp)
        movl    $0, %eax
        leave
        ret

以上就是C/C++ 函数原理传参示例详解的详细内容,更多关于C/C++ 函数原理传参的资料请关注编程网其它相关文章!

--结束END--

本文标题: C/C++函数原理传参示例详解

本文链接: https://www.lsjlt.com/news/174490.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C/C++函数原理传参示例详解
    目录x84-64的寄存器函数是个什么东西?一个简单的函数传参姿势入栈规则看看汇编全都存寄存器吗?传对象呢?x84-64的寄存器 本文所用gcc为 x86-64 gcc 10.1 w...
    99+
    2022-12-08
    C/C++ 函数原理传参 C/C++ 函数传参
  • C语言中变参函数传参的实现示例
    目录背景引入问题分析指针大小参数位置排布解决问题额外的测试总结参考资料背景引入 近期在看一本书,叫做《嵌入式C语言自我修养》,写的内容对我帮助很大,是一本好书。在第6章,GNU C编...
    99+
    2022-11-12
  • C#可变参数params示例详解
    目录前言示例探究本质扩展知识总结前言 前几天在群里看到群友写了一个基础框架,其中设计到关于同一个词语可以添加多个近义词的一个场景。当时群友的设计是类似字典的设计,直接添加k-v的操作...
    99+
    2022-11-13
  • python函数传参意义示例详解
    目录C++这样的语言用多了之后,在Python函数传递参数的时候,经常会遇到一个问题,我要传递一个引用怎么办? 比如我们想要传一个x到函数中做个运算改变x的值: def cha...
    99+
    2022-11-12
  • C++存储链接性原理示例详解
    目录链接性外部链接性单定义规则内部链接性无链接性总结链接性 链接性是指名称在不同文件之间能否共享,而作用域是指名称在文件内部哪些范围可见。 这里的文件并非开发时创建的文件,而是将文...
    99+
    2023-01-03
    C++存储链接性原理 C++ 存储链接性
  • 详解C++ sort函数的cmp参数
    目录1、升序排序2、降序排序3、结构体的排序实例前言: 学算法的第一天你在学冒泡、桶排 在你还没搞明白快排和归并的时候 你已经学到了数据结构最后的堆排序和希尔排序 可以说排序是很多竞...
    99+
    2022-11-12
  • C语言函数声明以及函数原型超详细讲解示例
    C语言代码由上到下依次执行,原则上函数定义要出现在函数调用之前,否则就会报错。但在实际开发中,经常会在函数定义之前使用它们,这个时候就需要提前声明。 所谓声明(Declaration...
    99+
    2023-02-11
    C语言函数声明 C语言函数原型 C语言函数声明与函数原型
  • C++ 线段树原理与实现示例详解
    目录一、问题引入二、线段树的构建三、线段树的单点修改与查询1、修改2、查询四、线段树的区间修改与查询1、修改2、查询一、问题引入 对于一般的区间问题,比如RMQ(区间的最值)、区间的...
    99+
    2022-11-13
  • C# Directory.GetFiles()函数案例详解
    C#中Directory.GetFiles() 函数的使用 C#中Directory.GetFiles(string path , string searchPattern, Sea...
    99+
    2022-11-12
  • C++ WideCharToMultiByte()函数案例详解
    函数WideCharToMultiByte() 详解 函数原型: int WideCharToMultiByte( UINT CodePage, DWORD dwFla...
    99+
    2022-11-12
  • C++ move()函数案例详解
    要了解move函数首先弄清左值引用和右值引用。 左值、左值引用、右值、右值引用 1、左值和右值的概念         左值是可以放在赋值号左边...
    99+
    2022-11-12
  • C语言可变参数函数详解
    目录C语言可变参数函数总结C语言可变参数函数 C 语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function)。这种函数需要固定数量的强制参数(manda...
    99+
    2022-11-12
  • C#中参数的传递方式详解
    值类型参数按值传递 class Program { static void Main(string[] args) { ...
    99+
    2022-11-13
    C# 传递参数
  • C++函数重载介绍与原理详解
    目录函数重载函数重载的概念函数重载的原理(名字修饰)总结:extern “C”函数重载 函数重载的概念 函数重载是函数的一种特殊情况,C++允许在同一作用域中...
    99+
    2022-11-12
  • 关于C/C++内存管理示例详解
    1、内存分配方式 在C++中,内存分成五个区,分别是堆、栈、自由存储区、静态存储区和常量存储区。 1) 栈 执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这...
    99+
    2022-11-12
  • C++递归与分治算法原理示例详解
    目录1. 汉诺塔问题2. 全排列问题3. 利用递归与分治策略寻找最大值4. 归并排序5. 快速排序6. 棋盘覆盖问题1. 汉诺塔问题   递归算法,分为 3 步:...
    99+
    2022-11-12
  • React.memo函数中的参数示例详解
    目录React.memo?这是个啥?React.memo的第一个参数父组件子组件React.memo优化React.memo的第二个参数父组件子组件React.memo优化父组件子组...
    99+
    2022-11-13
  • PythonFastAPI多参数传递的示例详解
    目录Python FastAPI请求参数传递FastAPI多参数传递类型路径多参数传递GET请求多参数传递POST请求多参数传递案例完整代码案例完整测试启动服务访问测试GET请求多参...
    99+
    2022-12-15
    Python FastAPI 多参数传递 Python FastAPI Python 参数传递
  • C# 总结QueueUserWorkItem传参几种方式案例详解
    最近在学习citrix的xenserver6.2的源代码,发现多处用到System.Threading命名空间下的ThreadPool.QueueUserWorkItem方法: ...
    99+
    2022-11-12
  • 如何理解C语言函数传参:指针的指针
    这篇文章主要介绍“如何理解C语言函数传参:指针的指针”,在日常操作中,相信很多人在如何理解C语言函数传参:指针的指针问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解C语言函数传参:指针的指针”的疑惑有所...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作