C++函数重载实现的原理以及为什么在C++中调用C语言编译的函数时要加上extern "C"声明

C++相对于C语言而言支持函数重载是其极大的一个特点,相信在使用C语言的时候大家如果要写一个实现两个整型数据相加的函数还要写一个浮点型数据相加的函数,那么这两个函数的名字绝对不可以一样,这样无疑在我们使用这个函数的时候增加了复杂性,但是在C++中我们却可以很好的解决这个问题,因为在C++中函数是支持重载的也就是说两个函数的函数名可以一样,这样并不会出现函数名重定义的问题,但是我们在使用的时候也要遵守一些规定,这些规定我们会在接下来的讨论中提到,下面我们就来分析在C++中函数是如何实现函数的重载的。

在这里我们用C语言和C++分别写两个函数,通过函数的符号表来观察函数名在经过编译之后究竟是什么形式的

下面就是我们的测试代码:

 1 #include<iostream>
 2
 3 using namespace std;
 4
 5
 6
 7 int Add(int x, int y)
 8
 9 {
10
11 int z = 0;
12
13 z = x + y;
14
15 return z;
16
17 }
18
19
20
21 double Add(double x, double y)
22
23 {
24
25 double z = 0;
26
27 z = x + y;
28
29 return z;
30
31 }
32
33
34
35 int main()
36
37 {
38
39 cout<<Add(1,3)<<endl;
40
41 cout<<Add(1.5,3.5)<<endl;
42
43 return 0;
44
45 }

在VS2008的编译环境下:

我们生成.map文件,然后可以查看函数在经过编译之后的函数名称为下图所示:

不难发现上图中函数命名的一些规律(当然这个规律只是片面的针对于VS2008编译环境):

1.以“?”开始和以”@Z”结尾

2.函数的名称紧接“?”之后

3.在函数明德后面分别是函数返回值类型修饰符、参数列表中的参数的类型修饰符

下面我们把这个相同的函数改为c语言的代码

代码如下:

 1 //#include<iostream>
 2
 3 //using namespace std;
 4
 5 #include<stdio.h>
 6
 7
 8
 9
10
11 int Add(int x, int y)
12
13 {
14
15 int z = 0;
16
17 z = x + y;
18
19 return z;
20
21 }
22
23
24
25 double Add(double x, double y)
26
27 {
28
29 double z = 0;
30
31 z = x + y;
32
33 return z;
34
35 }
36
37
38
39 int main()
40
41 {
42
43 //cout<<Add(1,3)<<endl;
44
45 //cout<<Add(1.5,3.5)<<endl;
46
47 return 0;
48
49 }

这时我们编译的话就会出现错误:

这里告诉我们函数名出现重定义

那么这是为什么呢?

这时我们注释掉一个函数然后编译后查看.map文件,查看函数重命名之后的名称

这里我们可以发现函数在编译之后重命名的名称仅仅只是在函数名称的前面加上了一个"_"(下划线),这样我们就不难分析了,C和C++编译的时候对函数的重命名机制是完全不一样的

1.C语言中仅仅只是在函数的名称的前面加上了"_"(下划线)

2.C++有自己的命名修饰规则,他会根据函数的参数列表中变量的类型等进行相应的类型修饰

虽然C++支持函数的重载但是我们在使用的时候也要注意以下几点:

1.函数的重载只是出现在同一作用域,例如假如两个工程里的函数名称相同,但是他们也不是函数的重载

2.函数名相同,函数的参数列表不同,返回值可同可不同,为什么函数返回值可同可不同呢?

这是因为在不同的编译环境下对于函数名称的修饰并不是相同的,下面就是在Linux环境下函数编译后重命名的形式:

仔细观察不难发现在Linux环境下的函数重命名的一些规则:

1.以“_Z”z作为开头,紧随其后的数字是函数名称的单词的个数

2.函数的名称后面有函数的参数列表中参数的类型修饰符,i是int型,d是double型

通过以上的阐述相信大家可以对C++中为什么可以实现函数重载有了清晰的认识,那么我们也就不难回答为什么在C++中调用被C编译过后的函数应该在前面加上 extern "C" 声明了。

这是因为我们当前是处于c++语言环境,这个时候我们如果不指定要调用的那个函数是用C语言编译的函数,那么当前在C++文件中编译时就会报错说是该函数是一个无法解析的外部符号,因为在编译运行的时候我们当前的程序会从符号表中去找相应的函数名,可是C++和C编译后生成的符号表中函数的名是不同的,那么这个函数也就是一个无法解析的外部符号了,但是当你用extern “C” 指明该函数是用C语言编译的函数,那么当前代码在编译运行的时候就会从用C语言编译的那个符号表文件中去查找相应的函数名,这样整个程序的编译运行费也就没有问题了。

时间: 2024-12-25 18:31:29

C++函数重载实现的原理以及为什么在C++中调用C语言编译的函数时要加上extern "C"声明的相关文章

java学习中,匿名函数、构造方法、构造代码块、构造方法中调用构造方法(java 学习中的小记录)

java学习中,匿名函数.构造方法.构造代码块.构造方法中调用构造方法(java 学习中的小记录) 作者:王可利(Star·星星) 匿名函数 匿名对象:没有名字的对象 匿名对象使用的注意点: 1.一般不会用匿名对象给属性赋值,无法获取属性值,每次new 都是一个新的对象. 2.匿名对象永远都不可能是一个对象. 如:person new().name = "星星":是不行的 匿名对象的好处:书写简单. 匿名对象使用的场景: 1.如果一个对象调用一个方法一次的时候,就可以用匿名对象来调用.

函数指针玩得不熟,就不要自称为C语言高手(函数指针是解耦对象关系的最佳利器,还有signal)

记得刚开始工作时,一位高手告诉我说,longjmp和setjmp玩得不熟,就不要自称为C语言高手.当时我半信半疑,为了让自己向高手方向迈进,还是花了一点时间去学习longjmp和setjmp的用法.后来明白那不单是跳来跳去那样简单,而是一种高级的异常处理机制,在某些情况下确实很有用. 事实上,longjmp和 setjmp玩得熟不熟与是不是C语言高手,不是因果关系.但是,如果可以套用那位高手的话,我倒想说如果函数指针玩得不熟,就不要自称为C语言高手.为什么这么说呢,函数指针有那么复杂吗?当然不是

Why? 在C++中调用被C编译后的函数,要在声明的前面加extern &quot;C&quot;

在C++程序中调用被C编译器编译后的函数,为什么要在声明的前面加extern "C"? 答:c语言不支持重载,C++支持重载 为了告诉编译器这个函数是C的编译风格,所以在找这个函数的时候也要按照C的风格去找 比如:在C++中写一个add函数 int add(int n1,  int  n2) 它找到的是?[email protected]@[email protected] ?函数名@@YA参数参数返回值@Z H代表int  M代表float @@YA表示开始      @Z表示结束

【python】如何在某.py文件中调用其他.py内的函数

假设名为A.py的文件需要调用B.py文件内的C(x,y)函数 假如在同一目录下,则只需 import B if __name__ == "__main__": B.C(x,y) 若只需调用单个函数,也可以 from B import C if __name__ == "__main__": C(x,y) 若A.py和B.py位于不同的目录下,可以用以下方法 (假设B.py位于D盘的根目录下) 1.引用所在路径 import sys sys.path.append(

python3中调用C语言的函数

一, 先用C语言写好一个函数库 #include<stdio.h> int add(int num1, int num2) { return num1 + num2; } int sub(int num1, int num2) { return num1 - num2; } int mul(int num1, int num2) { return num1 * num2; } int div(int num1, int num2) { return num1 / num2; } 二, 然后使用

php中调用类的属性和函数的方法-&gt;_=&gt;_::_$this-&gt;区别

在php中有同学经常搞不明白->,=>,::,$this->的作用,下面通过例子讲解下. 一.->用来引用一个类的属性(变量).方法(函数) 可以把->理解成调用的意思 如: <?php Class a{ Var $id; Function add(){ $this->id="test"; echo "abc"; } } $b = new a; $b->add();  //调用类a中的add()方法, 输出为abc E

在一个文件中调用另一个文件的函数

ceshi_1.c源码如下所示: #include<stdio.h> #include<sys/types.h> #include<stdlib.h> int f(int n); int main() {int n; printf("I LOVE YOU"); printf("\n"); printf("%d",f(3)); printf("\n"); return 0; } ceshi_2

C#中调用C++动态库的函数

[System.Runtime.InteropServices.DllImport("DebugToolWin",CallingConvention=CallingConvention.Cdecl)] //该语句是引入非托管代码程序集 public static extern bool DebugOutStr(string strValue); [System.Runtime.InteropServices.DllImport("DebugToolWin",Call

C++基础补遗篇—函数重载与Extern C

问题引出 之前提到C存在命名冲突问题,新的C++专门为此引入了namespace机制加以改进(后文介绍),此外还有另一种机制: int add(int i, int j) {    return i+i;  } float add(float a, float b, floatc)  {    return a+b+c;   } void main() { int a = add(8, 9); float b = add(7.7, 8.8, 9.9); } 上例在C环境下不成立,因为C编译器不允