当前位置: 首页 > news >正文

突破编程_C++_面试(基础知识(3))

面试题5:函数调用的过程

C++ 中函数的调用包含参数入栈、函数跳转、保护现场、回复现场等过程,重点过程如下:
(1)将函数的参数压入栈中,从右至左压入。
(2)调用函数时,将当前程序的执行位置(即返回地址)压入栈中。
(3)将函数的栈帧(也称为活动记录)压入栈中。栈帧包含了函数的局部变量、函数返回值、函数的上一级调用者的栈帧指针等信息。
(4)执行函数体内的语句,包括局部变量的声明和初始化、函数体语句的执行等。
(5)函数执行完毕后,将函数的返回值保存在寄存器中(或者栈中)。
(6)弹出函数的栈帧,并将返回值传递给上一级函数。
(7)将返回地址弹出栈中,程序跳转到该地址继续执行。
以如下代码为例( 64 位程序):

#include <iostream>int add(int a, int b)
{int sum = a + b;return sum;
}int main()
{int sum = add(1, 2);return 0;
}

首先给 main() 函数的第一行 int sum = add(1, 2); 打上断点,调试运行程序。
程序暂停后,查看当前汇编代码( VS2017 查看方法:右击当前代码页,选择转到反汇编):

int main()
{
00007FF67D8AA630  push        rbp  
00007FF67D8AA632  push        rdi  
00007FF67D8AA633  sub         rsp,108h  
00007FF67D8AA63A  lea         rbp,[rsp+20h]  
00007FF67D8AA63F  mov         rdi,rsp  
00007FF67D8AA642  mov         ecx,42h  
00007FF67D8AA647  mov         eax,0CCCCCCCCh  
00007FF67D8AA64C  rep stos    dword ptr [rdi]  
00007FF67D8AA64E  lea         rcx,[__81FC6F77_main2@cpp (07FF67D9E41D7h)]  
00007FF67D8AA655  call        __CheckForDebuggerJustMyCode (07FF67D874108h)  int sum = add(1, 2);
00007FF67D8AA65A  mov         edx,2  
00007FF67D8AA65F  mov         ecx,1  
00007FF67D8AA664  call        add (07FF67D87584Bh)  
00007FF67D8AA669  mov         dword ptr [sum],eax  return 0;
00007FF67D8AA66C  xor         eax,eax  
}

在汇编代码中,程序暂停在第 14 行(00007FF67D8AA65A mov edx,2)。后面的两行是传入参数的过程,其中,edx是数据寄存器,常用于存储一些大于 AX 寄存器的 16 位数和 32 位数的运算中的高位数。在函数调用中, edx 寄存器用于存储第一个参数值。ecx是计数寄存器,常用于存储循环计数器和移位操作的计数器。在函数调用中, ecx 寄存器用于存储第二个参数值。通过这两行传入的值可以看出,调用函数时,参数入栈时从右往左。
汇编行00007FF67D8AA664 call add (07FF67D87584Bh)用于跳转到待调用的函数内,但这里需要注意的是,地址07FF67D87584Bh并不是待调用的函数的地址,该代码会执行到下面这一行:

00007FF67D87584B  jmp         add (07FF67D8AA5C0h)  

这里的地址07FF67D8AA5C0h才是真正待调用函数的地址。下面即进入被调用函数内部:

int add(int a, int b)
{
00007FF67D8AA5C0  mov         dword ptr [rsp+10h],edx  
00007FF67D8AA5C4  mov         dword ptr [rsp+8],ecx  
00007FF67D8AA5C8  push        rbp  
00007FF67D8AA5C9  push        rdi  
00007FF67D8AA5CA  sub         rsp,108h  
00007FF67D8AA5D1  lea         rbp,[rsp+20h]  
00007FF67D8AA5D6  mov         rdi,rsp  
00007FF67D8AA5D9  mov         ecx,42h  
00007FF67D8AA5DE  mov         eax,0CCCCCCCCh  
00007FF67D8AA5E3  rep stos    dword ptr [rdi]  
00007FF67D8AA5E5  mov         ecx,dword ptr [rsp+128h]  
00007FF67D8AA5EC  lea         rcx,[__81FC6F77_main2@cpp (07FF67D9E41D7h)]  
00007FF67D8AA5F3  call        __CheckForDebuggerJustMyCode (07FF67D874108h)  int sum = a + b;
00007FF67D8AA5F8  mov         eax,dword ptr [b]  
00007FF67D8AA5FE  mov         ecx,dword ptr [a]  
00007FF67D8AA604  add         ecx,eax  
00007FF67D8AA606  mov         eax,ecx  
00007FF67D8AA608  mov         dword ptr [sum],eax  return sum;
00007FF67D8AA60B  mov         eax,dword ptr [sum]  
}

这段汇编代码的第 2 行到第 15 行之间是对该函数的栈初始化工作,由编译器自动添加。其中 rsp ( 32 位程序中是 esp ) 、rbp ( 32 位程序中是 ebp )、rdi ( 32 位程序中是 edi )是常用的寄存器:
rsp 为栈指针,常用来指向栈顶。上面汇编代码中第 6 行00007FF67D8AA5CA sub rsp,108h的意思是将栈顶指针往上移动 108h Byte。这个区域为间隔空间,将被调用的 add 函数与 main 函数的栈区域隔开一段距离,同时还要预留出存储局部变量的内存区域。
rbp 为基址指针,常用来指向栈底。
rdi 为目的变址寄存器。
上面汇编代码的第 17 行到第 21 行之间是进行两数相加的逻辑操作。
执行到第最后一行后打开寄存器查看器( VS2017 查看方法:调试–>窗口–>寄存器),可以查看到如下值:

RAX = 0000000000000003 RBX = 0000000000000000 RCX = 0000000000000003 RDX = 0000000000000002 RSI = 0000000000000000 RDI = 0000005BD30FFA58 R8  = 0000020993014F70 R9  = 0000005BD30FF954 R10 = 0000000000000013 R11 = 00000209930242E0 R12 = 0000000000000000 R13 = 0000000000000000 R14 = 0000000000000000 R15 = 0000000000000000 RIP = 00007FF67D8AA60B RSP = 0000005BD30FF950 RBP = 0000005BD30FF970 EFL = 00000206 0x0000005BD30FF974 = 00000003 

查看寄存器 RDI 的内存值( VS2017 查看方法:调试–>窗口–>内存->内存1):

0000005bd30ffb78 0000005bd30ffa90 00007ff67d8aa669 00007ff600000001 cccccccc00000002 cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc cccccccccccccccc

其中第三个值 00007ff67d8aa669 是 main 函数中调用该函数后的下一行汇编代码。
至此,整个调用过程结束。

面试题6:怎样判断两个浮点数是否相等

由于浮点数存入时有可能因为四舍五入而造成精度损失,所以两个浮点数直接用==操作符进行比较很可能会得到不符合预期的结果。
浮点数的比较应该使用如下方式:
对于浮点数而言比较合适的精度为:0.000001
对于双精度浮点数而言比较合适的精度为:0.0000000000000001
因此可以定义两个宏:

#define ACCURACY_F 1e-6
#define ACCURACY_D 1e-16

判断浮点数是否等于 0 :
float 类型:if(fabs(f) <= ACCURACY_F );
double 类型:if(fabs(d) <= ACCURACY_D);
判断两个浮点数是否相等:
float 类型:if(fabs(f1 - f2) <= ACCURACY_F);
double 类型:if(fabs(d1 - d2) <= ACCURACY_D);

相关文章:

突破编程_C++_面试(基础知识(3))

面试题5&#xff1a;函数调用的过程 C 中函数的调用包含参数入栈、函数跳转、保护现场、回复现场等过程&#xff0c;重点过程如下&#xff1a; &#xff08;1&#xff09;将函数的参数压入栈中&#xff0c;从右至左压入。 &#xff08;2&#xff09;调用函数时&#xff0c;将当…...

AI的安全应答之道

作者&#xff1a;统信UOS技术团队 2023,随着各种大语言模型的爆发&#xff0c;整个AI生态正处于从决策式AI进化到生成式AI的进程中。各类AI模型和AI应用层出不穷&#xff0c;也随之带来了与AI相关的各类潜在风险。AI开发和使用过程中的风险防范和治理&#xff0c;成为了不可忽…...

【昕宝爸爸小模块】日志系列之什么是分布式日志系统

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…...

如何在淘宝和Shopee上进行选品:策略和原则

在当今数字化时代&#xff0c;电商平台已经成为卖家们扩展业务和增加销售额的重要渠道。而在淘宝和Shopee这两个知名电商平台上进行选品时&#xff0c;卖家可以遵循一些相似的原则和策略&#xff0c;以确保他们的产品能够吸引目标客户并取得成功。本文将为您介绍一些在淘宝和Sh…...

C++/数据结构:二叉搜索树的实现与应用

目录 一、二叉搜索树简介 二、二叉搜索树的结构与实现 2.1二叉树的查找与插入 2.2二叉树的删除 2.3二叉搜索树的实现 2.3.1非递归实现 2.3.2递归实现 三、二叉搜索树的k模型和kv模型 一、二叉搜索树简介 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0…...

C++引用、内联函数、auto关键字介绍以及C++中无法使用NULL的原因

文章目录 一、引用1.1 引用概念1.2 引用特性1.3 常引用1.4 使用场景1.4.1 做参数1.4.2做返回值 1.5 引用和指针的区别1.6 小结一下 二、内联函数2.1 内联的概念2.2 内联的特性2.3 【面试题】 三、auto关键字(C11)3.1 类型别名思考3.2 auto简介 四、auto的使用细则4.1 基于范围的…...

RabbitMQ之三种队列之间的区别及如何选型

目录 不同队列之间的区别 Classic经典队列 Quorum仲裁队列 Stream流式队列 如何使用不同类型的队列​ Quorum队列 Stream队列 不同队列之间的区别 Classic经典队列 这是RabbitMQ最为经典的队列类型。在单机环境中&#xff0c;拥有比较高的消息可靠性。 经典队列可以选…...

【ArcGIS微课1000例】0099:土地利用变化分析

本实验讲述在ArcGIS软件中基于两期土地利用数据,做土地利用变化分析。 文章目录 一、实验描述二、实验过程三、注意事项一、实验描述 对城市土地利用情况进行分析时,需要考虑不同时期土地利用图层在空间上的差异性,如农用地转建筑用地的空间变化。而该变化过程表现为各时期…...

学习鸿蒙基础(2)

arkts是声名式UI DevEcoStudio的右侧预览器可以预览。有个TT的图标可以看布局的大小。和html的布局浏览很像。 上图布局对应的代码&#xff1a; Entry //入口 Component struct Index {State message: string Hello Harmonyos //State 数据改变了也刷新的标签build() {Row()…...

2024年美国大学生数学建模竞赛思路与源代码【2024美赛C题】

B站账号&#xff0c;提前关注&#xff0c;会有直播&#xff1a;有为社的个人空间-有为社个人主页-哔哩哔哩视频 (bilibili.com) 题目 待定 问题一 思路 待定 模型 待定 程序 待定 问题二 待定 思路 待定 模型 待定 程序 待定...

Windows11搭建GPU版本PyTorch环境详细过程

Anaconda安装 https://www.anaconda.com/ Anaconda: 中文大蟒蛇&#xff0c;是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。从官网下载Setup&#xff1a;点击安装&#xff0c;之后勾选上可以方便在普通命令行cmd和PowerShell中使用…...

Springboot项目基础配置:小白也能快速上手!

推荐文章 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;一&#xff09; 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;二&#xff09; 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;三&#xff09; 给软件行业带来了春天—…...

20240127在ubuntu20.04.6下配置whisper

20240131在ubuntu20.04.6下配置whisper 2024/1/31 15:48 首先你要有一张NVIDIA的显卡&#xff0c;比如我用的PDD拼多多的二手GTX1080显卡。【并且极其可能是矿卡&#xff01;】800&#xffe5; 2、请正确安装好NVIDIA最新的驱动程序和CUDA。可选安装&#xff01; 3、配置whispe…...

C# 递归执行顺序

为了方便进一步理解递归&#xff0c;写了一个数字输出 class Program {static void Main(string[] args){int number 5;RecursiveDecrease(number);}static void RecursiveDecrease(int n){if (n > 0){Console.WriteLine("Before recursive call do : " n);Rec…...

go 实现暴力破解数独

一切罪恶的来源是昨晚睡前玩了一把数独&#xff0c;找虐的选了个最难的模式&#xff0c;做了一个多小时才做完&#xff0c;然后就睡不着了..........程序员不能受这委屈&#xff0c;今天咋样也得把这玩意儿破解了 破解思路&#xff08;暴力破解加深度遍历&#xff09; 把数独…...

go语言-字符串处理常用函数

本文介绍go语言处理字符串类型的常见函数。 ## 多行字符串 在 Go 中创建多行字符串非常容易。只需要在你声明或赋值时使用 () 。 str : This is a multiline string. ## 字符串的拼接 go // fmt.Sprintf方式拼接字符串 str1 : "abc" str2 : "def" …...

DevOps落地笔记-05|非功能需求:如何有效关注非功能需求

上一讲主要介绍了看板方法以及如何使用看板方法来解决软件研发过程中出现的团队过载、工作不均、任务延期等问题。通过学习前面几个课时介绍的知识&#xff0c;你的团队开始源源不断地交付用户价值。用户对交付的功能非常满意&#xff0c;但等到系统上线后经常出现服务不可用的…...

vs 撤销本地 commit 并保留更改

没想到特别好的办法&#xff0c;我想的是用 vs 打开 git 命令行工具 然后通过 git 命令来撤销提交&#xff0c;尝试之前建议先建个分支实验&#xff0c;以免丢失代码&#xff0c; git 操作见 git 合并多个 commit / 修改上一次 commit...

深度解读NVMe计算存储协议-1

随着云计算、企业级应用以及物联网领域的飞速发展&#xff0c;当前的数据处理需求正以前所未有的规模增长&#xff0c;以满足存储行业不断变化的需求。这种增长导致网络带宽压力增大&#xff0c;并对主机计算资源&#xff08;如内存和CPU&#xff09;造成极大负担&#xff0c;进…...

CHS_06.2.3.4_2+用信号量实现进程互斥、同步、前驱关系

CHS_06.2.3.4_2用信号量实现进程互斥、同步、前驱关系 知识总览信号量机制实现进程互斥信号量机制实现进程同步信号量机制实现前驱关系 知识回顾 各位同学 大家好 在这个小节中 我们要学习怎么用信号量机制来实现进程的同步互制关系 知识总览 那么 我们之前学习了互斥的几种软…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...