Fork me on GitHub

现代 C++ 中的一次函数调用的工作流程

现代 C++ 中的一次函数调用的工作流程

ChatGPT 4o 给的答案:

  1. 函数声明解析

    编译器首先解析函数调用,确定要调用的函数。这包括 名称查找、重载解析和模板实例化

  2. 参数传递

    编译器检查传递的参数与函数签名是否匹配。如果有隐式类型转换,编译器会进行必要的类型转换。

    函数调用时,参数可以通过 值传递引用传递移动语义 传递给函数。C++ 11 引入了 右值引用和移动语义,允许将资源所有权从一个对象转移到另一个对象,以提高性能。

  3. 栈帧准备

    编译器生成代码,以便在调用函数之前准备栈帧。栈帧包含函数参数、返回地址和局部变量的空间。

  4. 函数调用指令

    编译器生成实际的调用指令,例如 CALL 指令(在 x86 架构上)。这回跳转到函数的入口地址。

  5. 函数执行

    函数体开始执行。此时,程序的控制权进入被调用函数,函数体的代码被逐条执行。

  6. 返回值处理

    如果函数有返回值,编译器会处理返回值的传递。返回值可以通过寄存器(例如 x86 架构上的 EAX 寄存器)或通过栈帧传递

  7. 栈帧清理

    函数执行完毕后,编译器生成代码以清理栈帧,恢复调用函数的上下文。这个过程包括恢复调用者的栈指针和返回地址。

  8. 返回调用点

    最终,函数执行 RET 指令(在 x86 架构上),将程序控制权返回给调用点,继续执行调用函数后的代码

1. 详细解释

1.1 函数声明解析

编译器在编译期间解析函数调用,进行名称查找和重载解析。对于模板函数,编译器还需要进行模板实例化

int add(int a, int b)
{
    return a + b;
}

int main()
{
    int result  = add(3, 4); // 函数声明解析
}

1.2 参数传递

编译器会根据函数签名确定参数如何传递。C++ 支持按值传递、按引用传递和按指针传递

void foo(int x, int& y, int* z)
{
    // ...
}

int a = 10;
int b = 20;
int c = 30;
foo(a, b, &c);		// 参数传递

1.3 栈帧准备

在函数调用之前,编译器生成代码以分配新的栈帧。这包括 分配函数参数和局部变量的空间

void bar(int x)
{
    int y = x * 2;
    // 栈帧准备
}

什么是栈帧,见 C++ 栈帧 StackFrame - icewalnut - 博客园 (cnblogs.com)

未完待续

posted @ 2024-06-17 10:14  icewalnut  阅读(5)  评论(0编辑  收藏  举报