C++----------函数的调用机制

  1. 栈帧的创建与销毁

    • 栈帧创建过程
      • 当一个函数被调用时,系统会在程序的栈空间中为该函数创建一个栈帧。首先,会将函数的返回地址(即调用该函数的下一条指令的地址)压入栈中,这确保函数执行完后能回到正确的位置继续执行后续代码。然后,根据函数参数的类型和数量,将参数的值(如果是值传递)或引用(如果是引用传递)或指针(如果是指针传递)依次压入栈中。最后,为函数内部定义的局部变量分配内存空间。
      • 例如,有函数void func(int a, int b),当调用func(3, 4)时,系统会先将返回地址压入栈,然后将34压入栈作为参数ab的值,接着为func函数内部可能定义的局部变量预留空间。
    • 栈帧销毁过程
      • 当函数执行结束(遇到return语句或者函数体的最后一个花括号)时,栈帧会被销毁。首先,会释放函数内部局部变量所占用的内存空间。然后,根据函数的返回值类型(如果有返回值),将返回值复制到一个临时存储位置(如果是基本数据类型)或者通过移动语义(如果是对象)将返回值传递给调用者。最后,将栈顶指针恢复到调用该函数之前的位置,这样就相当于销毁了这个栈帧,同时将返回地址从栈中弹出,程序继续从返回地址处执行。
  2. 参数传递方式的细节

    • 值传递深入理解
      • 复制过程:在值传递中,实际参数的值会被完整地复制到函数的形式参数中。对于基本数据类型,这是一个简单的字节复制过程。例如,传递一个int类型的参数,会将该int值的字节序列复制到函数参数对应的内存位置。对于自定义结构体等复杂类型,会递归地复制每个成员变量的值。
      • 对原始参数的影响:由于是复制了一份新的值给函数参数,所以在函数内部对参数的修改不会影响到原始的实际参数。例如,对于函数void modify(int num),在函数内部num = 10,但如果在函数外部有int original_num = 5; modify(original_num);original_num的值依然是5
    • 引用传递深入理解
      • 引用的本质:引用在底层实现上可以看作是一个指针常量,它总是指向被引用的对象。当进行引用传递时,实际上传递的是对象的地址,但是在语法上使用起来就像使用原始对象一样。例如,int& ref = original_num;reforiginal_num在内存中指向同一个位置。
      • 对原始参数的影响:因为引用和原始对象共享同一块内存空间,所以在函数内部通过引用对参数进行操作,实际上就是对原始对象进行操作。例如,函数void modifyByReference(int& num),在函数内部num = 10,如果在函数外部有int original_num = 5; modifyByReference(original_num);original_num的值会变为10
    • 指针传递深入理解
      • 指针的操作方式:指针传递是把变量的地址传递给函数。在函数内部,通过解引用指针(使用*操作符)来访问和修改指针所指向的变量的值。例如,函数void modifyByPointer(int* ptr),当传递&original_num作为参数时,在函数内部通过*ptr = 10来修改original_num的值。
      • 与引用传递的区别:虽然指针传递和引用传递都可以在函数内部修改原始变量的值,但指针传递需要显式地解引用指针来访问变量,而引用传递在语法上更简洁,直接使用引用变量就可以访问和修改原始变量。另外,指针可以在函数内部重新赋值指向其他对象,而引用一旦初始化就不能再引用其他对象。
  3. 函数返回值传递机制的细节

    • 基本数据类型返回值传递
      • 复制返回值:当函数返回一个基本数据类型(如intdouble等)的值时,函数会将返回值复制到一个临时存储位置。这个临时存储位置可能是一个寄存器或者栈中的某个位置,具体取决于编译器和硬件架构。例如,对于函数int add(int a, int b) { return a + b; },当调用add函数时,计算a + b的结果会被复制到这个临时位置,然后这个值再被赋值给接收返回值的变量(如int result = add(3, 5);中的result)。
    • 对象返回值传递
      • 返回值优化(RVO):当函数返回一个对象时,C++编译器可能会应用返回值优化。在没有返回值优化的情况下,函数会先创建一个临时对象,将函数内部的对象复制到这个临时对象中(通过调用复制构造函数),然后返回这个临时对象。但是,通过返回值优化,编译器可以直接将函数内部的对象构造到接收返回值的对象的内存空间中,避免了不必要的复制操作。例如,对于函数MyClass createObject(),如果MyClass是一个自定义类,在合适的条件下,编译器会直接将createObject函数内部构造的MyClass对象构造到接收返回值的MyClass对象中,而不是先复制到一个临时对象再进行赋值。
      • 移动语义(Move Semantics):如果编译器没有进行返回值优化,除了复制构造函数外,C++还提供了移动构造函数来更高效地处理对象返回值。移动构造函数允许将一个对象的资源(如动态分配的内存)“移动”到另一个对象中,而不是进行复制。例如,对于一个包含动态分配数组的类,移动构造函数可以将数组的指针从一个对象转移到另一个对象,避免了重新分配内存和复制数组元素的开销。当函数返回对象时,编译器可能会优先调用移动构造函数(如果定义了)来提高效率。
        在这里插入图片描述
        下面是一些代码示例,用来展示 C++ 函数的调用机制,包括栈帧、参数传递以及返回值传递相关内容:
#include <iostream>

// 用于展示栈帧中的局部变量
void localVarDemo() {
    int localVar = 10;
    std::cout << "局部变量 localVar 的值: " << localVar << std::endl;
}

// 值传递示例
void valuePassing(int num) {
    num = 20;
    std::cout << "值传递中函数内 num 的值: " << num << std::endl;
}

// 引用传递示例
void referencePassing(int& num) {
    num = 30;
    std::cout << "引用传递中函数内 num 的值: " << num << std::endl;
}

// 指针传递示例
void pointerPassing(int* num) {
    *num = 40;
    std::cout << "指针传递中函数内 *num 的值: " << *num << std::endl;
}

// 返回基本数据类型示例
int returnBasicType() {
    return 50;
}

// 简单类定义,用于展示对象返回
class MyClass {
public:
    int data;
    MyClass(int value) : data(value) {}
};

// 返回对象示例
MyClass returnObject() {
    MyClass obj(60);
    return obj;
}

int main() {
    // 栈帧中的局部变量演示
    localVarDemo();

    int value = 15;
    // 值传递
    valuePassing(value);
    std::cout << "值传递后 value 的值: " << value << std::endl;

    // 引用传递
    referencePassing(value);
    std::cout << "引用传递后 value 的值: " << value << std::endl;

    // 指针传递
    pointerPassing(&value);
    std::cout << "指针传递后 value 的值: " << value << std::endl;

    // 返回基本数据类型
    int basicResult = returnBasicType();
    std::cout << "返回基本数据类型的结果: " << basicResult << std::endl;

    // 返回对象
    MyClass objResult = returnObject();
    std::cout << "返回对象的 data 值: " << objResult.data << std::endl;

    return 0;
}

代码解释:

  • localVarDemo 函数展示了在栈帧中定义和使用局部变量,函数执行时会创建栈帧来存放 localVar
  • valuePassing 是值传递示例,函数接收参数的副本,所以内部修改不影响外部变量。
  • referencePassing 利用引用传递,函数形参是实参的别名,内部修改会同步到外部变量。
  • pointerPassing 通过指针传递,传递变量地址,函数可通过解引用修改外部变量的值。
  • returnBasicType 返回基本数据类型,返回值被复制给 basicResult
  • returnObject 返回自定义类对象,编译器可能会进行返回值优化,高效地把对象传递给 objResult
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/941622.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言初阶习题【9】数9的个数

1.编写程序数一下 1到 100 的所有整数中出现多少个数字9 2.思路 循环遍历1到100&#xff0c;需要判断每一位的个位数是否为9&#xff0c;十位数是否为9&#xff0c;每次符合条件就count进行计数&#xff0c;最后输出count&#xff0c;即可 3.code #define _CRT_SECURE_NO_W…

模型 课题分离

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。明确自我与他人责任。 1 课题分离的应用 1.1课题分离在心理治疗中的应用案例&#xff1a;李晓的故事 李晓&#xff0c;一位28岁的软件工程师&#xff0c;在北京打拼。他面临着工作、家庭和感情的多重…

Docker 入门:如何使用 Docker 容器化 AI 项目(一)

引言 在人工智能&#xff08;AI&#xff09;项目的开发和部署过程中&#xff0c;环境配置和依赖管理往往是开发者遇到的挑战之一。开发者通常需要在不同的机器上运行同样的代码&#xff0c;确保每个人使用的环境一致&#xff0c;才能避免 “在我的机器上可以运行”的尴尬问题。…

Android修行手册 - 移动端几种常用动画方案对比

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

抢单人机交互「新红利」!哪些细分赛道“多金”?

受终端用户的智能座舱体验需求驱动&#xff0c;视觉、听觉、触觉等人机交互方式加速焕新。 一方面&#xff0c;人机多模交互引领&#xff0c;车载声学进入新周期。根据高工智能汽车研究院统计数据&#xff0c;单车的车载扬声器搭载量正在快速起量。 很显然&#xff0c;作为智…

Linux shell脚本用于常见图片png、jpg、jpeg、webp、tiff格式批量添加文本水印

Linux Debian12基于ImageMagick图像处理工具编写shell脚本用于常见图片png、jpg、jpeg、webp、tiff格式批量添加文本水印 BiliBili视频链接&#xff1a; Linux shell脚本对常见图片格式转换webp和添加文本水印 在Linux系统中&#xff0c;使用ImageMagick可以图片格式转换&…

本地电脑使用命令行上传文件至远程服务器

将本地文件上传到远程服务器&#xff0c;在本地电脑中cmd使用该命令&#xff1a; scp C:/Users/"你的用户名"/Desktop/environment.yml ws:~/environment.yml 其中&#xff0c;C:/Users/“你的用户名”/Desktop/environment.yml是本地文件的路径&#xff0c; ~/en…

004最长回文子串

#include #include #include using namespace std; class Solution { public: string longestPalindrome(string s) { int n s.size(); if (n < 2) { return s; } int maxLen 1;int begin 0;// dp[i][j] 表示 s[i..j] 是否是回文串vector<vector<int>> …

蓝桥杯刷题——day8

蓝桥杯刷题——day8 题目一题干解题思路代码 题目二题干解题思路代码 题目一 题干 N 架飞机准备降落到某个只有一条跑道的机场。其中第i架飞机在 Ti时刻到达机场上空&#xff0c;到达时它的剩余油料还可以继续盘旋 Di个单位时间&#xff0c;即它最早可以于 Ti时刻开始降落&am…

ue5 pcg(程序内容生成)真的简单方便,就5个节点

总结&#xff1a; 前情提示 鼠标单击右键平移节点 1.编辑-》插件-》procedural->勾选两个插件 2.右键-》pcg图表-》拖拽进入场景 3.先看点point 右键-》调试(快捷键d)->右侧设置粒子数 3.1调整粒子数 可以在右侧输入框&#xff0c;使用加减乘除 4.1 表面采样器 …

【编辑器扩展】打开持久化路径/缓存路径/DataPath/StreamingAssetsPath文件夹

代码 [MenuItem("Assets/Open Explorer/PersistentDataPath")]public static void OpenPersistentDataPath(){Application.OpenURL(Application.persistentDataPath);}[MenuItem("Assets/Open Explorer/DataPath")]public static void OpenDataPath(){Appl…

STM32——“SPI Flash”

引入 在给单片机写程序的时候&#xff0c;有时会用到显示屏&#xff0c;就拿市面上的0.96寸单色显示器来说&#xff0c;一张全屏的图片就占用8x1281024个字节&#xff0c;即1kb的空间&#xff0c;这对于单片机来说确实有点奢侈&#xff0c;于是我买了一个8Mb的SPI Flash&#x…

Linux 下SVN新手操作手册

下面来介绍Linux 下 SVN操作方法&#xff1a; 1、SVN的安装 Centos 7 安装Subversion sudo yum -y install subversion Ubuntu 安装Subversion sudo apt-get install subversion 自定义安装&#xff0c;官方地址&#xff1a;https://subversion.apache.org/ 2、SVN的使用…

中国信通院致信感谢易保全:肯定贡献能力,期许未来合作

近日&#xff0c;中国信息通信研究院&#xff08;以下简称“中国信通院”&#xff09;向易保全发感谢信表达谢意&#xff0c;对其在中国信通院牵头的“铸基计划”——企业数字化转型高质量发展推进行动实施中展现出的重要贡献给予了高度评价和肯定&#xff0c;并展望了双方至20…

【微信小程序】1|底部图标 | 我的咖啡店-综合实训

底部图标 引言 在微信小程序开发中&#xff0c;底部导航栏&#xff08;tabBar&#xff09;是用户界面的重要组成部分&#xff0c;它为用户提供了快速切换不同页面的功能。今天&#xff0c;我们将通过一个实际案例——“我的咖啡店”小程序&#xff0c;来详细解析如何配置底部图…

(补)算法刷题Day24: BM61 矩阵最长递增路径

题目链接 思路 方法一&#xff1a;dfs暴力回溯 使用原始used数组4个方向遍历框架 &#xff0c; 全局添加一个最大值判断最大的路径长度。 方法二&#xff1a;加上dp数组记忆的优雅回溯 抛弃掉used数组&#xff0c;使用dp数组来记忆遍历过的节点的最长递增路径长度。每遍历到已…

基于单片机的智能电子秤(论文+源码)

1.设计框架 本次智能电子秤单片机控制系统由7个部分构成&#xff0c;包括手机&#xff0c;蓝牙传输模块&#xff0c;LCD液晶显示模块&#xff0c;单片机控制系统、压力传感器检测电路&#xff0c;按键电路以及复位晶振&#xff0c;整体框图如图2.1所示。在功能上&#xff0c;整…

【保姆级别教程】VMware虚拟机安装Mac OS15苹果系统附带【VMware TooLS安装】【解锁虚拟机】和【Mac OS与真机共享文件夹】手把手教程

目录 准备工作 一、安装虚拟机 二、解锁系统 三、安装系统 四、部署系统 五、安装VMware Tools(选做) 为什么要安装VMware Tools&#xff0c;这是啥玩意&#xff1f; 六、配置共享文件夹(选做) 为什么要共享文件夹&#xff1f; 注意事项&#xff1a; 七、安装完成 准…

【服务器】linux服务器管理员查看用户使用内存情况

【服务器】linux服务器管理员查看用户使用硬盘内存情况 1、查看所有硬盘内存使用情况 df -h2、查看硬盘挂载目录下所有用户内存使用情况 du -sh /public/*3、查看某个用户所有文件夹占用硬盘内存情况 du -sh /public/zhangsan/*

Etcd注册中心基本实现

Etcd入门 什么是Etcd GitHub&#xff1a;https://github.com/etcd-io/etcd Etcd数据结构与特性 键值对格式&#xff0c;类似文件层次结构。 Etcd如何保证数据一致性&#xff1f; 表面来看&#xff0c;Etcd支持事务操作&#xff0c;能够保证数据一致性。 底层来看&#xff0…