[C++] 深入理解C++函数重载底层原理 C++入门(2)

[C++] 深入理解C++函数重载底层原理 C++入门(2)本篇文章我们要深入理解函数重载。还不了解函数重载的小伙伴可以看看上篇文章末尾简单理解一下[C++]helloworld解析C++入门(一)本篇主要解决的问题:1.C语言不支持重载,C++支持重载,为什么?2.C++如何支持重载?目录问题的引入1.函数重载(C++)1.1编译链接过程1.1.1预处理1.1.2编译1.1.3汇编1.1.4链接2.C语言对函数重命名3.总结问题的引入首先我们复习一下函数重载。函数重载就像是一词多.

本篇文章我们要深入理解函数重载。还不了解函数重载的小伙伴可以看看上篇文章末尾简单理解一下[C++] helloworld 解析 C++入门(一)

本篇主要解决的问题:

1.C语言不支持重载,C++支持重载,为什么?

2.C++如何支持重载?

目录

问题的引入

1.函数重载(C++)

1.1编译链接过程

1.1.1预处理 

1.1.2编译

1.1.3汇编

1.1.4链接

2.C语言 对函数重命名

3.总结

问题的引入

首先我们复习一下函数重载。函数重载就像是一词多义,一个函数名可以有多个意思。函数可以根据参数的不同选择进入不同参数的函数。

那么,这种情况属于函数重载吗?

short Add(short left, short right)
{
}
int Add(short left, short right)
{
}

答:这种是不构成函数重载的,这是因为函数重载跟返回值没有关系,在VS2019下编译器也会主动报错。

那么今天我们就是来底层深挖,为什么和返回值没有关系,又为什么和参数的顺序,个数,类型有关系呢? 

[C++] 深入理解C++函数重载底层原理 C++入门(2)

1.函数重载(C++)

在我们学习C语言的过程中我们知道编译链接的过程,为了更好的展示这个过程,我们使用Linux来看这段过程。

1.1编译链接过程

首先我们复习一下编译连接的过程:

1、预处理 — 头文件展开,宏替换,条件编译,去掉注释
 f.i  test.i
2、编译 — 检查语法,生成汇编代码
 f.s  test.s
3、汇编 — 把汇编代码转换成二进制的机器码
 f.o  test.o
4、链接 — 找调用函数的地址,链接对应上,合并到一起 合并符号表
 a.out

 [C++] 深入理解C++函数重载底层原理 C++入门(2)

1.1.1预处理 

在预处理的过程中,会进行头文件的展开,宏替换,条件编译,去掉注释等一些操作,这个过程非常的重要。在这里我们重点说说头文件展开。

头文件展开:

假设现在我们创建一个f.h的头文件,f.cpp的文件。

[C++] 深入理解C++函数重载底层原理 C++入门(2)

[C++] 深入理解C++函数重载底层原理 C++入门(2)

 那么头文件的展开就是将f.cpp的头文件进行展开。如下图所示:

[C++] 深入理解C++函数重载底层原理 C++入门(2)

此时的cpp文件为:

 [C++] 深入理解C++函数重载底层原理 C++入门(2)

经过预处理的过程,我们在编译的过程中我们就可以找到函数了。 

1.1.2编译

检查语法,生成汇编代码,汇编代码是一种指令级的语言,如果有语法错误,就会在这个阶段出现。

我们在VS下看看什么是指令级的代码,这些指令级的代码是给CPU准备的,CPU是执行指令的。

例如:我们看看最简单的helloworld的指令代码

[C++] 深入理解C++函数重载底层原理 C++入门(2)

1.1.3汇编

当语法没问题的时候,我们就来到了汇编,此时这个指令级代码CPU不认识,机器都只认识0和1。因此汇编的过程就是将汇编代码转换成二进制的机器码。

1.1.4链接

找调用函数的地址,链接对应上合并到一起,合并符号表。

我们来理解一下这个过程:

这预处理过程中头文件展开如下

[C++] 深入理解C++函数重载底层原理 C++入门(2)

在编译的过程中还会生成一个符号表,主要记录函数定义和函数地址的映射,那符号表为什么要生成函数地址的映射呢。此时我们来看

[C++] 深入理解C++函数重载底层原理 C++入门(2)

 在main函数的指令中,有两句指令call,call后面所跟的就是函数的地址,函数的名字和函数的地址。然后我们来看一下这个过程,真正的函数地址就是第一句指令的地址。函数的名字也会有自己的命名规则。

[C++] 深入理解C++函数重载底层原理 C++入门(2)

[C++] 深入理解C++函数重载底层原理 C++入门(2)

 [C++] 深入理解C++函数重载底层原理 C++入门(2)

为了更好的看函数的命名规则,我们在linux下看看这个细节。当函数名相同,参数不同时,他们的函数名会有一套新的命名规则。在不同的话函数调用中,他们参数类型首字符带进命名规则中去了。

新的函数名:_Z 函数名长度 函数名 类型首字母

因此即使函数名相同,但参数的类型不同,顺序不同,个数不同都会产生不同新的函数名。

[C++] 深入理解C++函数重载底层原理 C++入门(2)

因此再调用的时候对应的名字是不相同的。因此所对应的地址也是不同的 

 [C++] 深入理解C++函数重载底层原理 C++入门(2)[C++] 深入理解C++函数重载底层原理 C++入门(2)

这也是为什么C++支持函数重载的原因。

2.C语言中处理

那我们在C语言中再看看这个过程,他的新的函数名是怎么命名的,我们首先创建3个文件

[C++] 深入理解C++函数重载底层原理 C++入门(2)

[C++] 深入理解C++函数重载底层原理 C++入门(2)

[C++] 深入理解C++函数重载底层原理 C++入门(2)

 我们再在Linux下看看C语言是如何处理函数名的

[C++] 深入理解C++函数重载底层原理 C++入门(2)

[C++] 深入理解C++函数重载底层原理 C++入门(2)

此时我们发现C语言对函数的命名只有函数名本身,和参数无关。

我们在Linux下看看报错信息:我们创建两个f函数,我们在Linux下用gcc编译看报错信息,我们发现这时就会报错说函数命名发生冲突。

[C++] 深入理解C++函数重载底层原理 C++入门(2)

因此我们知道C语言对函数的命名只有函数名本身,因此如果在C语言中,函数名相同时,就会报错,因此C语言是不支持函数重载的。

3.总结

1.C++支持函数重载是因为C++在符号表中存储的函数的定义和函数的地址。C++中对函数的命名规则有了新的变化:_Z 函数名长度 函数名 类型首字母 。

因此参数的类型,个数,顺序不同就会不同的命名。名字不同地址不同。这也是为什么C++支持函数重载的原因。

2.我们发现在新的命名规则中是不包括返回值类型的,因此返回值类型不同并不会对函数的命名产生影响,这也是返回值不构成函数重载的原因。

short Add(short left, short right)
{
}
int Add(short left, short right)
{
}

3.C语言中在生成符号表中存储的只是原函数的名字,那么如果函数的名字相同时就会产生命名冲突。这就是为什么C语言不支持函数重载的原因。

(本篇完)

今天的文章[C++] 深入理解C++函数重载底层原理 C++入门(2)分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/11165.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注