从汇编的角度揭秘C++函数重载,原来这么简单

article/2025/8/22 11:42:59

函数重载是指在同一个作用域内,有多个同名函数,但是它们的形参列表不同。在调用时,根据不同的实参,调用相应的函数。函数重载是一种静态多态形式。我们先来看一个函数重载的例子,然后分析其背后的原理。请看下面这段代码:

#include <stdio.h>int sum(int a, int b) 
{int ret =  a + b; printf("int type, sum = %d\r\n", ret); return ret;
}float sum(float a, float b)
{float ret =  a + b; printf("float type, sum = %f\r\n", ret); return ret;
}int main()
{int i = 1, j = 2;float h = 1.0, k = 2.0; printf("first call\r\n");sum(i, j);printf("second call\r\n");sum(h, k);return 0;
}

上面这段代码定义了两个同名函数:sum,但是形参不一样。在main函数中分别用两个int形,两个float型的变量去调用sum函数。期望的结果是:两个int型变量作为型参,会调用第一个sum函数。两个float型变量作为型参,会调用第二个sum函数。编译以及运行结果:

从输出结果来看,第一次调用第一个sum函数,第二次调用第二个sum函数。实现了静态多态的一个实现。其背后的原理是什么呢?为什么在同一个作用域内,有两个相同名的函数不会有编译错误呢?查看一下可执行文件的汇编代码:

objdump -s -d function_loading > resultvi result

找到main函数汇编代码:

00000000000011f7 <main>:11f7:       f3 0f 1e fa             endbr6411fb:       55                      push   %rbp11fc:       48 89 e5                mov    %rsp,%rbp11ff:       48 83 ec 10             sub    $0x10,%rsp1203:       c7 45 f0 01 00 00 00    movl   $0x1,-0x10(%rbp)120a:       c7 45 f4 02 00 00 00    movl   $0x2,-0xc(%rbp)1211:       f3 0f 10 05 33 0e 00    movss  0xe33(%rip),%xmm0        # 204c <_IO_stdin_used+0x4c>1218:       001219:       f3 0f 11 45 f8          movss  %xmm0,-0x8(%rbp)121e:       f3 0f 10 05 2a 0e 00    movss  0xe2a(%rip),%xmm0        # 2050 <_IO_stdin_used+0x50>1225:       001226:       f3 0f 11 45 fc          movss  %xmm0,-0x4(%rbp)122b:       48 8d 05 fe 0d 00 00    lea    0xdfe(%rip),%rax        # 2030 <_IO_stdin_used+0x30>1232:       48 89 c7                mov    %rax,%rdi1235:       e8 26 fe ff ff          callq  1060 <puts@plt>123a:       8b 55 f4                mov    -0xc(%rbp),%edx123d:       8b 45 f0                mov    -0x10(%rbp),%eax1240:       89 d6                   mov    %edx,%esi1242:       89 c7                   mov    %eax,%edi1244:       e8 20 ff ff ff          callq  1169 <_Z3sumii>1249:       48 8d 05 ec 0d 00 00    lea    0xdec(%rip),%rax        # 203c <_IO_stdin_used+0x3c>1250:       48 89 c7                mov    %rax,%rdi1253:       e8 08 fe ff ff          callq  1060 <puts@plt>1258:       f3 0f 10 45 fc          movss  -0x4(%rbp),%xmm0125d:       8b 45 f8                mov    -0x8(%rbp),%eax1260:       0f 28 c8                movaps %xmm0,%xmm11263:       66 0f 6e c0             movd   %eax,%xmm01267:       e8 38 ff ff ff          callq  11a4 <_Z3sumff>126c:       b8 00 00 00 00          mov    $0x0,%eax1271:       c9                      leaveq1272:       c3                      retq1273:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)127a:       00 00 00127d:       0f 1f 00                nopl   (%rax)

这里大家如果看不懂或者不熟悉汇编,也没关系。重点关注这两条命令:

1244:       e8 20 ff ff ff          callq  1169 <_Z3sumii>

1267:       e8 38 ff ff ff          callq  11a4 <_Z3sumff>

call指令用于函数的调用,所以这两条指令分别是调用_Z3sumii以及_Z3sumff函数。对照main函数源码,可以看出,是这两条源码:

sum(i, j);

sum(h, k);

但是这里有点奇怪,源代码中是sum函数,在汇编里面怎么是_Z3sumii以及_Z3sumff呢。其实原理是,c++编译器会对函数名进行修饰。sum函数的后缀ii以及ff分别是代表形参分别是int和int,以及float和float。即一个sum函数经过修饰之后,变成了两个不同名的函数_Z3sumii以及_Z3sumff。为了验证这个结论,可用如下命令:

> nm function_loading | grep sum

输出如下:
00000000000011a4 T _Z3sumff
0000000000001169 T _Z3sumii
说明function_loading中定义了_Z3sumff以及_Z3sumii这两个符号。但这两个符号是修饰后的结果,那么修饰前的符号是怎么样的呢?通过以下命令:

>c++filt _Z3sumff

输出如下:

sum(float, float)

>c++filt _Z3sumii

输出如下:

sum(int, int)

跟源码正好匹配上。说明_Z3sumff是sum(float, float)修饰后的结果,_Z3sumii是sum(int, int)修饰后的结果。验证了前面的结论:sum函数的后缀ii以及ff分别是代表形参分别是int和int,以及float和float。即一个sum函数经过修饰之后,变成了两个不同名的函数_Z3sumii以及_Z3sumff。

从此,我们可以看出C++的函数重载的原理是C++编译器会对符号进行修饰。虽然函数名是一样的,但是经过修饰之后,函数名就不一样了。也就不会造成符号表冲突。

此文章的B站视频:用汇编深入剖析C++函数重载机制,原来这么简单_哔哩哔哩_bilibili

 

 


http://www.hkcw.cn/article/liDrlQJMMg.shtml

相关文章

Sigma-Aldrich胰蛋白酶细胞解离方案速览

Sigma-Aldrich_胰蛋白酶用于细胞培养 细胞解离是细胞传代过程中的一个步骤&#xff0c;即细胞从预处理表面分离&#xff0c;形成悬浮液。这些悬浮液对于传代培养重新接种、细胞计数分析和细胞增殖非常重要。有多种蛋白水解酶可用来从粘附基质上脱离细胞&#xff0c;胰蛋白酶就…

金正恩:炮兵部队随时能战且战之必胜!

金正恩:炮兵部队随时能战且战之必胜!据朝中社报道,朝鲜人民军大联合部队炮兵部队于29日进行了火炮射击比赛,朝鲜劳动党总书记、国务委员长金正恩亲临现场观摩。金正恩对比赛成果予以高度评价,他指出,参赛炮兵部队充分展现了炮兵武装力量的实战能力,时刻保持着万全的临战…

保健品,为何总在“围猎”老年人?

近日,市场监管总局在全国部署开展老年人药品、保健品虚假宣传专项整治工作,打击药品、保健品市场“坑老”“骗老”行为。各地市场监管部门将聚焦老年人药品、保健品领域,依法查处虚假宣传、价格欺诈、违法广告、非法添加等侵害老年人合法权益、破坏市场竞争秩序的行为。同时…

立志成为一名优秀测试开发工程师(第八天)——jemeter的学习

jemeter的学习 目录 一、jemeter常见元件的认识 二、jemeter手动设计脚本 三、jemeter工具录制脚本 一、jemeter常见元件的认识 ①测试计划&#xff1a;所有元件的父级文件&#xff08;容器&#xff09;&#xff0c;在所有元件的最顶层 其他元件都是基于测试计划来组织的…

如何使删除的数据不可恢复?

一些无用的数据包含我们计算机上的重要信息。如果你想让这些数据彻底不可恢复&#xff0c;你需要了解必要的数据擦除方法和一些有用的技巧。继续阅读并轻松获得解决方案。 第 1 部分&#xff1a;我可以使已删除的数据不可恢复吗&#xff1f; 是的&#xff0c;完全有可能使已删…

35岁小伙不结婚 爆改山洞隐居4年:美色不值得浪费时间金钱!

35岁小伙不结婚爆改山洞隐居4年。近日,一35岁小伙爆改山洞隐居4年引发网友热议,采访中他表示美色不值得自己浪费时间金钱,成本太高了。叫世外桃源也不为过,山洞门前有小河,门口可以种菜,而山洞用红砖建造,也非常现代化,有电脑和家具一应俱全的,书房是自己空间!建造一…

【Git】View Submitted Updates——diff、show、log

在 Git 中查看更新的内容&#xff08;即工作区、暂存区或提交之间的差异&#xff09;是日常开发中的常见操作。以下是常用的命令和场景说明&#xff1a; 文章目录 1、查看工作区与暂存区的差异2、查看提交历史中的差异3、查看工作区与最新提交的差异4、查看两个提交之间的差异5…

连接远程桌面计算机提示:“这可能是由于CredSSP加密数据库修正” 问题解决方案

连接远程计算机提示&#xff1a;“这可能是由于CredSSP加密数据库修正” 问题解决方案 1.连接远程计算机提示&#xff1a;“这可能是由于CredSSP加密数据库修正” 问题 2. win R,输入gpedit.msc&#xff0c;打开本地组策略编辑器 2.1 操作步骤&#xff1a;计算机配置–>系…

切片器导航-大量报告页查看的更好方式

切片器导航-大量报告页查看的更好方式 现在很多报告使用的是按钮导航&#xff0c;即使用书签按钮来制作页面导航的方式。但是当我们的报告有几十页甚至上百页的时候&#xff0c;使用书签按钮来制作页面导航&#xff0c;无论是对于报表制作者还是报告使用者来说都是一种很繁琐的…

AI智能体|扣子(Coze)搭建【自动生成超高质量PPT】工作流

各位好久不见&#xff0c;你的失踪人口又回来了&#xff0c;已经超过一周的时间没有进行文章的更新了。 没更新的这段时间&#xff0c;主要还是因为工作上的调整以及身体生病所导致的停更&#xff0c;具体以后再说。 我们先讲今天的主要主题&#xff0c;使用 Coze 智能体一键生…

day39python打卡

知识点回顾 图像数据的格式&#xff1a;灰度和彩色数据模型的定义显存占用的4种地方 模型参数梯度参数优化器参数数据批量所占显存神经元输出中间状态 batchisize和训练的关系 作业&#xff1a;今日代码较少&#xff0c;理解内容即可 一、 图像数据的介绍 1.1 灰度图像 从这里开…

Azure Devops pipeline 技巧和最佳实践

1. 如何显示release pipeline ? 解决方法: 登录devops, 找到organization - pipeline - setting下的Disable creation of classic release pipelines,禁用该选项。 然后在project - pipeline - setting,禁用Disable creation of classic release pipelines 现在可以看到r…

艺人李嘉琦回母校重庆大学开讲座 分享追梦历程

5月29日,演员李嘉琦回到母校重庆大学,参加新闻学院“优秀校友回母校”系列讲座。她以“梦想?梦幻?人生也是一部电视剧”为主题,与学弟学妹们分享了自己在母校时的学习生活和进入娱乐圈的奋斗经历。李嘉琦从小就有当演员的梦想,但不知道如何实现。高考时,她从内蒙古考入重…

定位例子(vue3)

定位 https://juejin.cn/post/7398348521135767567 一固定定位 1.1 固定定位是相对于根元素的&#xff0c;或说固定在浏览器视窗。

DSPE-PEG2000-Mal和DSPE-PEG2000-NHS偶联多肽的对比

1.结构区别&#xff1a; DSPE-PEG2000-MAL 的结构中包含马来酰亚胺&#xff08;Mal&#xff09;基团&#xff0c;这能够与含有巯基&#xff08;-SH&#xff09;的分子发生选择性反应&#xff0c;如半胱氨酸。它主要用于构建靶向脂质体&#xff0c;通过与特定的靶向分子结合实现…

数据库 1.0.3

数据库的数据类型问题 到目前为止实习的话百分之50都够用了 现在只是认识一下数据类型&#xff0c;还轮不到你一个实习生来写表 查询数据库不是想的那么简单 对于mysql&#xff0c;常用的数据类型就那几个 但是有的公司要求类型比较严格&#xff0c;在定义的时候感觉浪费几个空…

字节开源BAGEL可文生图、图像理解、图像编辑

BAGEL是由字节跳动开源的通用多模态大模型&#xff0c;一个原生支持多模态输入输出 思维链推理 MoE 架构优化的跨模态超级 AI。 话不多说&#xff0c;咱们今天来试着复现下。 1、下载代码&#xff0c;创建环境 git clone https://github.com/bytedance-seed/BAGEL.gitcd BA…

PaddleOCR本地部署 (Python+Flask)

查看配置&#xff1a; win10系统Python 3.9.13 NVIDIA GeForce RTX 3080 Ti 安装环境&#xff1a; 1&#xff09;下载 CUDA Toolkit 12.6 2&#xff09;安装 CUDA Toolkit 查看是否安装成功 nvcc --version3&#xff09;安装 PaddlePaddle GPU 版本&#xff08;配合 CU…

CSformer:结合通道独立性和混合的稳健多变量时间序列预测

原文地址&#xff1a;2312.06220 发表会议&#xff1a;AAAI 2025 代码地址:暂无 作者&#xff1a;王浩鑫 团队&#xff1a;四川大学 本博客内容主要介绍了此论文到底做了什么&#xff1f;以及我阅读中遇到的一些问题。 因为我本人就是时序预测方向的所以我直接借用AI助手对…

springcloud openfeign 请求报错 java.net.UnknownHostException:

现象 背景 项目内部服务之间使用openfeign通过eureka注册中心进行服务间调用&#xff0c;与外部通过http直接调用。外部调用某个业务方提供的接口需要证书校验&#xff0c;因对方未提供证书故设置了忽略证书校验代码如下 Configuration public class IgnoreHttpsSSLClient {B…