一、C++是C的升级,为啥两者不能直接相互调用?
1、我们知道,代码从编写,到能执行之前,仍需要经过编译(.obj)、链接阶段(.exe)。通常,编译每一个单元文件会生成目标文件,
然后链接器会把各个目标文件链接起来生成可执行性文件。
2、链接器之所以能把目标文件相互之间链接起来,就是通过查找目标文件中的唯一函数符号(即经过编译器去编译修饰后,重新得到的函数符号)。
但是C和C++编译器对编译函数符号的生成规则是不一样的,
为什么C和C++编译之后的函数名会不一样?
因为C语言只有单一的命名空间,不支持函数重载,所以不允许同名函数的存在,但是C++允许有多个命名空间,
支持函数重载,也允许同名函数的存在(通过参数类型和个数的不同进行区分)
举个例子:C和C++对函数void GetNum()编译之后产生的函数符号
C:_GetNum()
C++:编译的时候会把括号内的参数也当成函数名的一部分,比如:
GetNum(int a)翻译成_GetNum_int
GetNum(int a,int b)翻译成_GetNum_int_int
因为编译过程中产生的函数符号不一样,在连接的时候就无法找到匹配的符号去链接,所以无法混合调用
二、解决办法----->关键字extern实现C/C++的混合调用
用链接指示声明:extern "C"{/*函数名*/}告诉编译器以C的方式进行编译函数
extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。
注意:extern "C"只能在C++的编译环境中使用,在C环境中使用会出错
举个例子有这些文件main.cpp、GetMax.c、GetMax.h
1、在GetMax.h文件中声明该函数在C++环境下的编译方式
#ifndef _GetMax_h_ #define _GetMax_h_ //extern声明的作用是让main.cpp文件调用GetMax()这个函数的时候按照C的方式编译 #ifdef __cplusplus extern "C" { #endif // !__cplusplus int GetMax(int a,int b); #ifdef __cplusplus } #endif // !__cplusplus #endif
2、在GetMax.c文件中实现函数
#include"GetMax.h" int GetMax(int a,int b) { return a > b ? a : b; }
3、在main.cpp文件中调用GetMax.c中实现的方法
#include<iostream> #include"GetMax.h" using namespace std; int main() { int n = GetMax(1, 2); printf("%d\n", n); system("pause"); return 0; }
2、在C中调用C++的函数
第一种:.C文件调用.cpp文件中的函数
有文件main.c、GetMax.cpp
1、在GetMax.cpp中先声明当前系统编译此函数的方式为C
extern "C" int GetMax(int a, int b); int GetMax(int a, int b) { return a > b ? a : b; }
2、在main.c文件中用extern声明函数getMax()为外部函数
#include<stdio.h> #include"GetMax.h" extern int GetMax(int a, int b); int main() { int n = GetMax(1, 2); printf("%d\n", n); system("pause"); return 0; }
第二种:.C文件调用.cpp文件中的类(C中没有类的方法,所以要先把类封装成函数,在给C调用)
有文件main.c、GetMax.cpp、
1、在.cpp文件中实现类,然后封装类里面的方法
extern "C" int GetMax(int a, int b); class TestA { public: int GetMax_(int a, int b) { return a > b ? a : b; } }; int GetMax(int a, int b) { TestA A; return A.GetMax_(a, b); }
2、在.C文件中声明外部函数
#include<stdio.h> #include"GetMaxClass.h" extern int GetMax(int a, int b); int main() { int n = GetMax(1, 2); printf("%d\n", n); system("pause"); return 0; }