1.1 为什么需要混合编程
Cpp是从C演变过来的,C有很多优秀成熟项目和库,没必要在C++中重写,C++程序可以直接调用调用
庞大项目划分后一部分适合用C(底层),一部分适合用C++(中间层、上层)
1.2 混合编程的支撑
编译型程序的编译过程:源文件->目标(库)文件->可执行程序->镜像文件
任何编程语言执行时都必须是可执行程序,所以都必须先被编译成目标文件
混合编程的“混合”操作发生在链接这一步
二、C和C++混合编程的解决方案
通过前面的研究我们可以知道C和C++本质上是可以混合编程的,但是生成的中间符号名称不同,所以链接器在进行链接时会出问题,那如何解决呢?
2.1 先谈谈__cplusplus
__cplusplus是C++中预定义的一个标准宏,为长整型,其值为cpp标准的年月;在C中是未进行定义的,可以用来检测编译环境
2.2 extern “C”{}
用extern “C”{}可以使{}中的内容用C的标准来编译
#ifndef __TEST_H_
#define __TEST_H_
#ifdef __cplusplus
extern "C"
{
#endif
int func1();
#ifdef __cplusplus
}
#endif
#endif
2.3 解决方案
通过2.2我们可以知道在C++的头文件中只要把函数的声明放在extern “C”{}的大括号范围之内,就可以让g++在编译这个函数时生成中间符号名时按照C的规则而不是按照C++的规则,所以这样的函数就可以和C的库进行共同链接。但是,在C语言中,extern “C”{}是未被定义的
所以我们将__cplusplus和extern “C”{}结合使用,通常有以下两种情况:
三、两种常见情况
3.1 同一个项目中C是库,C++是源码,C++调用C
这是最常见的情况,我们只需要在C的头文件中加上extern "C"的声明,在C++中直接包含头文件调用。后继直接用g++编译链接即可
如果我们同时有C和Cpp的源码,我们也是只需要在C的.h库函数中加入__cplusplus和extern “C”{},对于Cpp的.hpp文件不做任何改动,最后统一进行g++编译即可
g++ main.cpp test.c -o main.elf
3.2 同一个项目中C++是库,C是源码,C调用C++
如果我们只有C++库而源码是C,我们最后只能用gcc编译链接,这带来了很多麻烦:
gcc main.c -c -o main.o
g++ test. -c -o test.cpp.o
gcc main.o test.cpp.o -o main.elf
g++和gcc的编译时符号差异
c++支持很多c并不支持的特性,如函数重载
而C++继承了C的所有特性,也就是说C编译时无法直接像C++一样使用特定的语句实现编译Cpp时按照C的规则。但是,我们可以用cpp写一层封装层,加上extern “C”,
#ifndef __TEST_H_
#define __TEST_H_
#ifdef __cplusplus
extern "C"
{
#endif
int func1();
#ifdef __cplusplus
}
#endif
#endif
在只有C++库而源码是C的情况下,使用封装层的技巧就是封装层使是用g++编译,但是只在封装头文件函数声明中加了extern “C”,而调用的C++静态库函数的#include未加,因此调用的函数还是按C++的规则解析,制作库时可以实现连接。在C源码中调用封装库,巧妙避免了直接使用C++库由于临时符号不同导致的链接错误
总之,
源码是CPP,调用库是C,只用g++ 编译;
源码是C,调用库是CPP,CPP的头文件加入
#ifdef __cplusplus
extern "C"
{
}
用g++ -c *.cpp -o **.cpp.o 生成cpp.o
用gcc -c main.c -o main.o 生成c.o
gcc main.o **.cpp.o -o target.elf 生成最终文件