最近在工作在遇到需要在C语言程序里调用C++库的问题,这次将这个问题总结记录一下。
1、关于为什么需要C和C++混合编程
我们知道C语言和C++各自有更适合的领域,比如在嵌入式开发中,底层操作系统以及音视频开发通常使用C语言,而应用层开发通常使用的是C++。
2、为什么不同的语言可以混合编程
(1)程序编译的过程:高级语言->汇编语言->二进制代码->链接->可执行程序->烧录镜像;
(2)任何语言最终都要变成二进制的可执行程序才能在CPU上运行,不同的高级语言在编译成汇编语言的过程是不一样的,所以每种高级语言都有自己的编译器;
(3)不管哪种高级语言在汇编语言阶段或者二进制代码阶段时都是一样的格式,互相之间是可以调用的,也就是我们常看到的库文件,开发中常把代码编译成库供其他人调用;
(4)高级语言的目标都是编译成汇编指令,汇编指令是和CPU相关而与高级语言无关,所以CPU相同的情况下,每种高级语言在汇编阶段都是统一的;
3、解决思路
在实际编程中我们通常认为C++是对C语言的扩充和延申,并且对C语言提供后向兼容的能力。C++支持的某些特性在C语言中并不支持,所以C++在需要和C对接的部分不能采用C++的特性,而应该使用C语言的风格来编写代码。
依据这一思路,可以在C++中使用extern “C”{}将需要和C对接的部分括起来,表示该部分向C兼容。
3.1、extern “C”{}使用示例
#ifdef __cplusplus
extern "C"{
#endif
······
#ifdef __cplusplus
}
#endif
4、C++调用C:C是库
4.1.、C函数代码:cTest.c
int add(int a, int b)
{
return a+b;
}
4.2、C头文件:cTest.h
#ifndef __CTEST_H__
#define __CTEST_H__
#ifdef __cplusplus
extern "C"{
#endif
int add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
4.3、C++调用代码:cppTest.cpp
#include <iostream>
#include "cTest.h"
using namespace std;
int main()
{
int a = 1;
int b= 2;
cout << add(a, b) << endl;
return 0;
}
4.4、编译链接代码
4.4.1、使用extern “C”{}
[root#]$ ls
cppTest.cpp cTest.c cTest.h
[root#]$
[root#]$ gcc -c cTest.c -o cTest.o
[root#]$
[root#]$ ar -r libcTest.a cTest.o
ar: creating libcTest.a
[root#]$
[root#]$ g++ cppTest.cpp -L. -lcTest
[root#]$
[root#]$ ls
a.out cppTest.cpp cTest.c cTest.h cTest.o libcTest.a
[root#]$
[root#]$ ./a.out
3
4.4.2、不使用extern “C”{}
root#]$ g++ cppTest.cpp -L. -lcTest
/tmp/cc0Wckzc.o: In function `main':
cppTest.cpp:(.text+0x21): undefined reference to `add(int, int)'
collect2: ld returned 1 exit status
报错!!
总结:用C语言写功能库代码时,需要对外提供的函数接口头文件用extern “C”{}括起来,将来库无论被C语言调用还是被C++调用都支持。
5、C调用C++:C++是库
5.1、C++函数代码:cppTest.cpp
#include "cppTest.hpp"
int add(int a, int b)
{
return a+b;
}
5.2、C++头文件:cppTest.hpp
#ifndef __CPPTEST_HPP__
#define __CPPTEST_HPP__
int add(int a, int b);
#endif
5.3、C调用代码:cTest.c
#include <stdio.h>
#include "cppTest.hpp"
int main()
{
int a = 1;
int b= 2;
printf("a+b=%d\n", add(a, b));
return 0;
}
这样会报错
5.4、解决方案:将C++库再封装一层wrapper文件
5.4.1、封装的C++源文件:cppPack.cpp
#include "cppPack.hpp"
#include "cppTest.hpp"
int addPack(int a, int b)
{
return add(a, b);
}
5.4.2、封装的C++头文件:cppPack.hpp
#ifndef __CPPPACK_HPP__
#define __CPPPACK_HPP__
#ifdef __cplusplus
extern "C"{
#endif
int addPack(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
5.4.3、C调用代码:cTest
#include <stdio.h>
#include "cppPack.hpp"
int main()
{
int a = 1;
int b= 2;
//这里调用封装的addPack函数,addPack函数内部就是调用的add函数
printf("a+b=%d\n", addPack(a, b));
return 0;
}
5.4.4、编译链接代码
root@ubuntu:# g++ cppPack.cpp -c -o cppPack.o
root@ubuntu:# ar -r libcppPack.a cppPack.o
root@ubuntu:# gcc cTest.c -L ./ -lcppPack -lcppTest -I ./
成功!!