深剖函数重载——C++基础篇

目录

    • 传统艺能
    • 程序的运行机制
    • 函数重载的深度内涵
    • extern “C”
    • C 调 C++?
    • 静态库的创建
    • 引用

传统艺能

小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】
乔乔的gitee代码库(打灰人 )欢迎访问,点我!

非科班转码社区诚邀您入驻
小伙伴们,打码路上一路向北,背后烟火,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我

倾力打造转码社区微信公众号,等你加入!
深剖函数重载——C++基础篇_第1张图片


深剖函数重载——C++基础篇_第2张图片

程序的运行机制

我们之前学习过程序的预处理机制,预处理这步会去掉注释,宏替换,头文件展开以及条件编译(详见俺之前的笔记),假如这里有一个程序包含了== new.h , new.cpp 和 test.c ,预处理完了变成 == new.i , test.i

接着编译步骤会去检查语法并生成汇编代码,程序报错会在编译这一步发生,编译处理完后变成== new.s, test.s==,所以之前说的缺省参数为什么要在声明(.h)给出而不在定义(.cpp)给出就是因为如果有缺省参数,函数的声明和调用就应该匹配,否则编译就会报错。

汇编出的代码就是指令级的语言,也就是代码转到反汇编后的一句一句代码,编译没问题后就会将代码转换成指令,这些指令都是给 CPU 准备的,CPU就是去执行指令的,那他是怎么支持的呢?CPU对每条指令他都支持了一个指令级,每个指令级要做什么事他都可以做,比如调用函数的 call 指令等等。当然,汇编代码不是 CPU 认识的 0,1 二进制代码,CPU:请打开麦克风交流!所以汇编就是翻译出二进制机器码,这一步会生成 == new.o, test.o==。
深剖函数重载——C++基础篇_第3张图片

链接为什么说是链接而不是直接合并呢?其实他的本质就是去链接库并找到调用函数地址,链接对应上合并在一起。我们从两个方面来看,我们预处理阶段就把 new.h 展开在头上了,也就是我们有了 .h 里面函数的声明了,而我们在调用他里面包含的函数名时,函数一来就会先创建栈帧,有栈帧就必定有地址,有地址才能被调用。

链接过程还会生成一个符号表函数调用指令符号表主要记录了函数名称和函数地址的映射。这些内容是为了在有人调用这个函数的时候能够执行 call 指令(call + 函数地址 是在调用函数),如果出现 “链接错误” 那他并不是语法错误,可能是声明了函数而没有写定义之类的让链接过程找不到。

函数重载的深度内涵

我们之前说C++里面特色的函数重载,而C语言不支持,那C++到底是如何支持的?而C语言又是为何不支持?要明白这些问题首先要知道程序的运行机制包括预处理,编译,汇编,链接

==所以C语言之所以不支持函数重载是因为C语言函数名是用的原来自己的名字 ,就会发生冲突!==而C++支持函数重载是因为C++会发生函数名修饰,修饰基本规则是 _Z + 函数名 + 类型首字母,比如 void func(int a,double b)命名出来就是 _Zfuncid,Linux环境下是这样命名的。

链接时找到函数的地址来填上,当然他也可以链接其他库,比如别人开源写了一个数据库,库里面又一些 API ,在C和C++里面我们叫他静态库或动态库。库是 C 的 cpp 能调用,是 cpp 的 C 也能调用,这种交叉调用这么神奇?
深剖函数重载——C++基础篇_第4张图片

但是交叉调用有一个鸿沟,其实这个过程和上面一样,编译好了到符号表里面去找,这里会在链接时去对应库里面去找,直接找是找不到的!和函数重载是一样的,那我该怎么找啊?这里又引入一个新的概念 extern “C”

extern “C”

这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern "C"就是其中的一个策略。

对于 cpp 内函数名是修饰过的,C 又是没修饰的 , extern “C”就可以改变链接或编译方式来帮助我们 C 调 cpp 或者 cpp 调 C

C++代码调用C语言代码,在C++的头文件中使用或者在多个人协同开发时,可能有的人比较擅长C语言,而有的人擅长C++,这些个情况下 extern “C” 就有大显身手的机会。

如此一来我们 C++ 想调 C 就简单了,直接加上一句

extern "C"
{
   #include "file"//file文件名,如.lib、.h
}

他就是在告诉编辑器声明的函数是 C 函数,要用 C 的方式去链接调用。C 调 C++ 有一些些不一样了,我们可以把之前的条件编译的宏拿来好好玩玩

#ifdef __cplusplus
     #define _C extern "C"
#else
     #define _C
#endif

__cplusplus 是C++天生就自己定义的标识符,代码中的 extern “C” 全部替换成 _C,条件编译只要满足C++条件就放出后面带有 extern “C” 声明的 _C 宏标识。当然 extern “C” 可以放在函数名前面也可以括起来多个函数声明。

C 调 C++?

C程序是可以调用 C++ 的,但是并不常见,已知的一个 google 的项目,他们写的 tc_malloc ,用来替代 C语言里面的 malloc,他们觉得多线程下 tc_malloc 比 malloc 更高效,而 tc_malloc 的实现基础是 C++,如果一个C语言项目想用他也是可以的,只需要对暴露的关键函数加上 extern “C”就行。

深剖函数重载——C++基础篇_第5张图片

静态库的创建

我们在 C++ 项目里面直接引用 C 的头文件是施行不通的,我们可以自己创建一个静态库,以 vs 为例,空项目基础上右键属性,常规选中配置类型改为静态库
深剖函数重载——C++基础篇_第6张图片
debug 下生成的就不是 .exe 而是 .lib 了,他就是静态库,我们要想在 C++ 程序里面链接 C 的静态库,一样的右键属性,链接器里面常规选中附加库目录,可以在电脑中浏览想添加的库

深剖函数重载——C++基础篇_第7张图片
然后再找到输入栏的附加依赖项,将添加的静态库名称加到这里的最前面,前后用分号隔开一下更好。
深剖函数重载——C++基础篇_第8张图片

原理就是我们程序链接时会去目录下找库,找到静态库 .lib 里面有对应的符号表,映射和 C++ 一样的指令即可

引用

这里的引用不是新定义的一个变量,而是给已经存在的变量取了一个别名,编译器不会为引用变量开辟空间,他和他的引用变量共用一块内存空间,就好比你叫某某某,但江湖上人们都叫你帅哥或者美女。

int a = 1;
int& b = a;

这里 b 就是 a 的引用也叫做 a 的别名,他们的地址都是一样的,同一块空间的内容 a 和 b 都可以去修改和访问,他的价值就是比如我们需要造一个含有指针参数的函数,取地址很麻烦的,我们可以让形参是实参的别名,这样就不用取地址就爽多了,引用的使用还是非常方便的。

今天就先到这里吧,摸了家人们

你可能感兴趣的:(C++,C++,预处理机制,函数重载,底层原理)