C++ | 探究函数重载的原理:函数名修饰【基于Windows + Linux双系统】

news2024/10/7 8:24:16

在这里插入图片描述

在这里插入图片描述

文章目录

  • 一、前言
    • 【中国乒乓和中国男足】
    • 【文言文一词多义】
  • 二、函数重载概念引入
    • 1、参数【类型】不同构成重载
    • 2、参数【个数】不同构成重载
    • 3、参数【类型顺序】不同构成重载
  • 三、函数重载的原理
    • 1、回顾程序编译 + 链接的过程
    • 2、Linux下【objdump】查看反汇编
    • 3、Windows下反汇编查看
    • 4、函数名修饰规则总结
  • 解答:为何而C语言不支持函数重载❓
  • 错误案例分析🔍
  • 四、总结与提炼

一、前言

【中国乒乓和中国男足】

网上呢一直流传着这么两个说法,我国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!

  • 相信了解的读者就可以看出来这两句话的不同含义了,虽然都叫做【谁也赢不了】,但是呢因为这个所指代的对象不一样也就造成了这两句话的意思不同
  • 其实对于函数重载来说也具有相同的意味,虽然看上去一样,但因为某些内容不一样便造成了函数重载

在这里插入图片描述

【文言文一词多义】

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了

  • 相信你在上初高中的时候一定学习过文言文,里面有一种东西叫做 —— 一词多义,也就是对于一个词来说可以存在不同的含义,它所存在的语境不同就会导致它的意思有所不同
  • 从编程语言的角度来说就可以说这个词被重载了,虽然都是一个词,但却具有不同的含义

在这里插入图片描述
通过上述两个生活小案例,相信你对函数重载一定有了一个基本的概念,接下去让我们正式来学习一下函数重载💻

二、函数重载概念引入

【函数重载】:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题

  • 对于函数重载这个概念,我们在学习C语言的时候是没有听过的,因为在C语言中是不存在函数重载概念的。只有在.cpp的文件中,我们才可以进行函数重载

在这里插入图片描述
在这里插入图片描述
对于C++中的函数重载来说,随着不同类型或者个数的实参传入,编译器会自动识别向对应的函数去进行一个调用

1、参数【类型】不同构成重载

  • 首先第一种就是【类型】不同可以构成函数重载,这个类型值得不仅仅是返回值类型,更重要的是对于形参的类型
  • 可以看到,下面的两个函数虽然函数名相同,但是因为形参的类型不同,所以可以处理的数据种类就不一样
int Add(int x, int y)
{
	return x + y;
}

double Add(double x, double y)
{
	return x + y;
}
int ret1 = Add(1, 2);
double ret2 = Add(1.1, 2.2);
  • 运行结果就不展示了,我们可以通过调试去观察一下编译器是对于重载的函数是否真的可以做到一个自动识别

在这里插入图片描述

2、参数【个数】不同构成重载

  • 第二种的话就是传入实参的个数不同也会可以构成重载。可以看到我写了一个三参的Add函数
int Add(int x, int y)
{
	return x + y;
}

int Add(int x, int y, int z)
{
	return x + y + z;
}
int ret1 = Add(1, 2);
int ret2 = Add(1, 2, 3);
  • 同样,我们通过调试来观察程序的思维

在这里插入图片描述

3、参数【类型顺序】不同构成重载

  • 最后一种的话可能你没有听说过,若是形参的两个类型顺序发生了改变,那也可以算是函数重载
void Print(int x, char c)
{
	cout << x << " ";
	cout << c << " ";
	cout << endl;
}

void Print(char c, int x)
{
	cout << c << " ";
	cout << x << " ";
	cout << endl;
}
Print(1, 'x');
Print('y', 2);
  • 可以看出,编译器依旧会进行一个自动识别

在这里插入图片描述

三、函数重载的原理

  • 对于函数重载的原理就是 —— 采用了函数名修饰,所以编译器可以通过修饰后的不同的函数去找到对应的函数

1、回顾程序编译 + 链接的过程

在观察函数重载的原理之前,我们来浅浅回顾一下C语言中所介绍的程序编译+链接全过程

  • 我们知道,要诞生一个可执行程序,就需要经过【翻译环境】和【运行环境】,我们主要讨论的是前者。而对于前者,又可以细分为【编译】+ 【链接】这两个过程,在经过编译器进行预编译、编译、汇编之后,之前的源文件test.c就会形成一个目标文件test.o
  • 但是在一个目录下,可能存在多个源文件,一个文件又可能调用了另一个文件,那此时它们就都需要进行编译产生.o的目标文件

在这里插入图片描述

  • 但是对于目标文件来说是不可以直接被执行的,因此需要将当前目录下生成的多个目标文件经过链接器进行链接,若是在目标文件中还使用到了库中的函数,那么链接器就会到库中去寻找对应的库函数,一起进行链接
  • 最终形成的才是一个可执行文件.exe,在Linux下是a.out

在这里插入图片描述


现在我们要去思考的一个点是,假如test.cpp中使用到了add.c中的函数Add,而且恰好这个函数还进行了函数重载,那编译器是怎么知道要去add.c中寻找这个重载函数的呢❓

首先你要清楚在编译阶段后的【链接】阶段,它的功能是什么

  1. 合并段表
  2. 符号表的合并和符号表的重定位
  • 当链接器进行链接的时候,它看到test.o中调用到了Add函数,此时它就会去其他目标文件中通过一定的方式识别找到它所匹配调用的这个重载函数,然后通过将两个目标文件的符号表进行合并也就形成了最后的可执行文件

在这里插入图片描述
但是还有一点很困惑的是,编译器是怎样的方式去识别的呢?我们可以通过查看【反汇编】代码来观察一下

2、Linux下【objdump】查看反汇编

首先我们来看下Linux平台下对于重载函数的反汇编指令是怎样的

  • 首先生成一下这个可执行文件。然后我使用到的一个是查看目标文件或者可执行的目标文件的构成的gcc工具 —— objdump。这个也是Linux下的一个指令,感兴趣的可以去了解一下 链接

在这里插入图片描述

  • 此时我们就可以来看一下生成的反汇编指令是怎样的,直接拉到重载的两个Add函数这里
  • 可以看到,原本的第一个函数定义变成了<_Z3Addii>,第二个函数则变成了<_Z3Adddd>这是为什么呢?

在这里插入图片描述

  • 为了进行对于,我在也写了一份C语言的代码,并且使用gcc去进行了一个编译。同样我们也可以去查看它的反汇编指令
  • 此时便观察到C语言对于函数名在编译 + 链接之后并没有做什么过多的修改,而是直接使用的原来的函数名【这里只有一个函数的原因是C不支持函数重载】

在这里插入图片描述
所以我们可以得出结论:对于C语言来说是不存在函数名修饰的,只有C++支持,会将函数参数类型信息添加到修改后的名字中

在这里插入图片描述

3、Windows下反汇编查看

Linux中查看完之后我们再来Windows中来看看,为什么要先看Linux呢?看下去你就知道了

  • 在VS2019中因为屏蔽了过多细节,所以我使用VC6.0进行一个演示【此时你就就可以看出在Windows下的函数名修饰是相当得复杂】

请添加图片描述

  • 一样,通过C和C++两个源程序进行运行,因为我处在VS这个集成开发环境中,所以不需要对源文件进行编译 + 链接,只需点击运行即可
  • 可以看到,对于.cpp的文件来说,函数名在修饰之后变得是异常复杂。可是对于.c的文件来说,使用的还是原先的Add函数名,没有发生变化

在这里插入图片描述

  • 本来想观察一下Windows环境下的函数名修饰,但是如此复杂度的规则这可如何是好呢?那我们就稍微地来聊一聊有关Windows下的【函数名修饰规则】

在这里插入图片描述
看了上面这些我想应该也够了,如果你还想要再深度地进行了解的话可以看看这篇文章 —— 链接

4、函数名修饰规则总结

通过上面的观察我们就可以来总结一下有关函数名的修饰规则

  • 在Linux环境下,C++的函数名修饰规则为【_Z + 函数长度 + 函数名 + 类型首字母】
    • Linux下的编译器为gcc/g++,一个开源组织搞的项目
  • 在Windows环境下,C++的函数名修饰规则为 【? + 函数名 + @@YA + 返回值 + 参数1 + 参数2 + @Z】,int类型对应的是字母H,void类型对应的是字母X,double类型对应的是字母N。扩展:float类型对应的是字母M(可以当做了解一下
    • Windows下的编译器是cl.exe,集成在VS中,是由微软公司发布的

解答:为何而C语言不支持函数重载❓

在看了上面有关C++函数重载的原理之后,就可以回答为何C语言不支持函数重载

  • 因为对于C语言来说,在经过编译后函数名修饰不会发生任何的改变,还是采用原先的函数名,若是想C++那样写重载函数的话就会别编译器认为是语法错误。因为编译器无法通过不同的函数名修饰去找到对应所调用的函数
  • 所以就可以看出对于C++的函数重载而言是通过修饰后的函数名去进行比对的,无论是Windows还是会Linux都是一样,只是不同的平台拥有各自的编译器,每个编译器所规定的语法是不同的

错误案例分析🔍

通过研究了函数重载的原理之后,最后再来说说比较容易误解的写法,你认为下面的两个函数构成函数重载吗?

int Add(int x, int y)
{
	return x + y;
}

double Add(int x, int y)
{
	return x + y;
}
  • 【答案揭晓】:No,这样不可以构成函数重载,仅仅是返回值的不同无法编译器认定为是函数重载,因为对于函数名和形参类型完完全全相同的两个函数在进行函数名修饰之后也是一样的

在这里插入图片描述
在这里插入图片描述

  • 可以看到,无论是对于Windows还是Linux下,连编译都是通不过的,所以函数重载只有三种形式,不要搞混淆了

四、总结与提炼

最后我们来总结一下本文所学习的的内容📖

  • 首先在文章的开始,我通过两个生活中的小案例先带读者了解了什么是函数重载的概念。然后讲述了有关函数重载的三种形式,分别是:【类型】不同、【个数】不同和【类型顺序】不同三种。对函数重载有了一个基本的认识
  • 然后我们便通过双系统深入探究了对于C++而言对函数在编译之后会进行一个函数名修饰,Linux环境下易理解一些,Windows环境下的解析过于复杂,若是有兴趣的读者可以继续深入

以上就是本文要介绍的所有内容,感谢您的阅读🌹

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven安装与配置,IDEA配置Maven

文章目录1. 安装本地Maven2. 安装3. 配置环境变量4. 配置settings.xml文件5. IDEA配置1. 安装本地Maven 官网下载&#xff1a;https://maven.apache.org/download.cgi 2. 安装 把下载好的maven压缩包解压到一个没有中文&#xff0c;空格或其他特殊字符的文件夹&#xff0c;…

数据结构与算法基础(王卓)(15):KMP算法详解(含速成套路和详细思路剖析)

如果时间不够&#xff0c;急&#xff08;忙&#xff09;着应付考试没心思看&#xff0c;直接参考&#xff08;照抄&#xff09;如下套路&#xff1a; PART 1&#xff1a;关于next [ j ] PPT&#xff1a;P30 根据书上以及视频上给出的思路&#xff08;提醒&#xff09;&#x…

JSONP劫持

注意&#xff1a;仅用于技术讨论&#xff0c;切勿用于其他用途&#xff0c;一切后果与本人无关&#xff01;&#xff01;&#xff01; 个人博客地址&#xff1a;HJW个人博客 扩展&#xff1a; 面试问题&#xff1a;CSRF的两种方法中&#xff0c;CORS和JSONP的区别&#xff1…

dubbo进阶——服务导出

服务导出 在这里记录一下对" Dubbo 导出服务的过程"的研究。 触发时机 public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEv…

代码随想录--数组--螺旋矩阵题型

n等于几&#xff0c;螺旋矩阵最外层行列数就等于几。如n等于3所以最外层一圈的行、列都是3个数字&#xff0c;如左图&#xff0c;n等于4所以最外层的行、列都是4个数字&#xff0c;如右图&#xff1a; 题目要求我们输出(以n3为例)[[123][894][765]]&#xff0c;题目只是给我们一…

MySQL:索引与事物

目录 简单了解索引的底层数据结构 索引的概念&#xff1a; 索引存在的意义&#xff1a; 索引的使用&#xff1a; 索引实现的数据结构 B树 B 树 B 树的特点 B 树的优势 事物 事物的概念 事物的使用 事物的四大特性 并发可能引起的问题 脏读问题 不可重复读 幻读…

未系安全带识别系统 yolo

未系安全带识别系统通过pythonyolo智能视频分析技术&#xff0c;未系安全带识别算法对画面中高空作业人员未系安全带行为进行监测&#xff0c;未系安全带识别算法监测到人员未穿戴安全带时&#xff0c;立即通知后台人员及时处理触发告警。Yolo算法采用一个单独的CNN模型实现end…

算法24:LeetCode_并查集相关算法

目录 题目一&#xff1a;力扣547题&#xff0c;求省份数量 题目二&#xff1a;岛屿数量 题目三&#xff1a;岛屿数量拓展 什么是并查集&#xff0c;举个简单的例子。学生考试通常会以60分为及格分数&#xff0c;我们将60分及以上的人归类为及格学生&#xff0c;而60分以下归…

mysql学习之数据系统概述

☀️马上要成为打工人&#xff0c;这几天把前面的知识都捡了捡&#xff0c;发现自己对关系数据库这块的学习还有所缺失&#xff0c;于是本章开始学习mysql 这里写目录标题1. 数据库系统的发展1.1 人工管理阶段1.2 文件系统阶段1.3 数据库阶段1.4 大数据阶段2 数据库系统的组成2…

扬帆优配|2600亿汽车巨头闪崩近9%,汽车股惊现“冰火两重天”!

今日早盘&#xff0c;A股全体低开震荡调整&#xff0c;首要股指跌逾1%&#xff0c;科创板体现略强&#xff0c;盘中一度直线拉升翻红&#xff0c;两市一度近4200股下跌。 盘面上&#xff0c;轿车服务、信创、半导体等板块相对强势&#xff0c;轿车整车、超导概念、一体压铸、建…

【MySQL】MySQL的索引

目录 介绍 索引的分类 索引的操作-创建索引-单列索引-普通索引 格式 操作 索引的操作-创建索引-单列索引-唯一索引 索引的操作-创建索引-单列索引-主键索引 索引的操作-创建索引-组合索引 索引的操作-全文索引 索引的操作-空间索引 索引的验证 索引的特点 介绍…

Lazada、Allegro、速卖通测评自养号技术(方法解析)

无论是亚马逊、拼多多Temu、shopee、Lazada、wish、速卖通、煤炉、敦煌、雅虎、eBay、TikTok、Newegg、乐天、美客多、阿里国际、沃尔玛、OZON、Joom、Facebook、Coupang、独立站、Cdiscount、Kaufland、DARTY、Allegro、MANO等平台测评自养号对于卖家来说算是一种低成本、高回…

什么?你不知道 ConcurrentHashMap 的 kv 不能为 null?

一、背景 最近设计某个类库时使用了 ConcurrentHashMap 最后遇到了 value 为 null 时报了空指针异常的坑。 本文想探讨下以下几个问题&#xff1a; &#xff08;1&#xff09; Map接口的常见子类的 kv 对 null 的支持情况。 &#xff08;2&#xff09;为什么 ConcurrentHashM…

Ethercat学习-电机调试问题总结

文章目录问题1&#xff1a;初始化不进入OP状态问题2&#xff1a;PDO通讯数据不对主站硬件&#xff1a;STM32F405LAN8720A主站软件&#xff1a;SOEM 问题1&#xff1a;初始化不进入OP状态 现象描述&#xff1a;主站初始化过程中&#xff0c;打印信息显示状态一直在safe-op&…

多态且原理

多态 文章目录多态多态的定义和条件协变&#xff08;父类和子类的返回值类型不同&#xff09;函数隐藏和虚函数重写的比较析构函数的重写关键字final和override抽象类多态的原理单继承和多继承的虚函数表单继承下的虚函数表多继承下的虚函数表多态的定义和条件 定义&#xff1…

Python批量爬取游戏卡牌信息

文章目录前言一、需求二、分析三、处理四、运行结果前言 本系列文章来源于真实的需求本系列文章你来提我来做本系列文章仅供学习参考阅读人群&#xff1a;有Python基础、Scrapy框架基础 一、需求 全站爬取游戏卡牌信息 二、分析 查看网页源代码&#xff0c;图片资源是否存在…

Node.js + MongoDB 搭建博客 -- 登录页面

准备工作 安装Node.js安装express等相关库MongoDB数据库电脑系统&#xff1a;win11 功能分析 搭建一个简单的具有多人注册、登录、发表文章以及登出功能的博客。 设计目标 未登录&#xff1a;主页左侧导航栏显示home、login、register&#xff0c;右侧显示已发表的文章、发…

视觉SLAM14讲第三章习题作业

这是本人的解答&#xff0c;并非官方解答 验证旋转矩阵是正交矩阵 在第44页中&#xff0c;旋转矩阵的引入是这样的&#xff1a; 所以&#xff0c;我们需要验证矩阵 R[e1Te1′e1Te2′e1Te3′e2Te1′e2Te2′e2Te3′e3Te1′e3Te2′e3Te3′]R \begin{bmatrix} e_1^{T}e_1^{}&am…

【Java开发】设计模式 02:工厂模式

1 工厂模式介绍工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使…

Weblogic管理控制台未授权远程命令执行漏洞复现(cve-2020-14882/cve-2020-14883)

目录漏洞描述影响版本漏洞复现权限绕过漏洞远程命令执行声明&#xff1a;本文仅供学习参考&#xff0c;其中涉及的一切资源均来源于网络&#xff0c;请勿用于任何非法行为&#xff0c;否则您将自行承担相应后果&#xff0c;本人不承担任何法律及连带责任。 漏洞描述 Weblogic…