C调用C++和C++调用C
原创
©著作权归作者所有:来自51CTO博客作者喜欢打篮球的普通人的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
1.C调用C++
若C调用的是C++全部函数的代码
- 将函数用extern "C"声明;;
然后C代码中不要include C++的头文件, 而采用直接在C中增加函数声明的方式; - C调用C++,使用extern "C"则是告诉编译器依照C的方式来编译封装接口,当然接口函数里面的C++语法还是按C++方式编译
方法1(需要改动以前的C++代码):
C++代码
/*C++ code*/
extern "C" void f(int);
void f(int i)
{
// your code
}
C语言代码
void f(int); // 不引入, 而只是直接声明
void cc(int i)
{
f(i); //调用
// other code
}
若C调用的是C++成员函数的代码
- 如果想要调用C++类中的成员函数, 由于C中没有类, 因此需要一个包装函数来调用这个成员函数, 并返回结果;
- 如果你想要在C里调用成员函数(包括虚函数),则需要提供一个简单的包装(wrapper)
方法2(需改动以前的C++代码):
// C++ code:
class C
{
// ...
virtual double f(int);
};
extern "C" double call_C_f(C* p, int i) // wrapper function
{
return p->f(i);
}
/* C code: 调用C::f()*/
double call_C_f(struct C* p, int i);
void ccc(struct C* p, int i)
{
double d = call_C_f(p,i);
/* ... */
}
方法3(不改动以前的C++代码):
- C代码.c只能调用C的函数,所以可以用包裹函数去包裹C++函数,然后把这个包裹函数以C的规则进行编译,这样C就可以调用这个包裹函数了
C++代码
CppAdd.h
int cppadd(int x, int y);
CppAdd.cpp
#include "CppAdd.h"
#include <stdio.h>
int cppadd(int x, int y) {
printf("from C++ function.\n");
return (x + y);
}
编译静态库 libCppAdd.a
g++ -c CppAdd.cpp
ar -r libCppAdd.a CppAdd.o
C++代码(包裹函数)
CppAddWrapper.h
#ifdef __cplusplus
extern "C" {
#endif
int cppaddwrapper(int x, int y);
#ifdef __cplusplus
}
#endif
CppAddWrapper.cpp
#include "CppAddWrapper.h"
#include <stdio.h>
#include "CppAdd.h"
int cppaddwrapper(int x, int y) {
printf("from wrapper.\n");
int sum = cppadd(x, y);
return sum;
}
编译wrapper静态库 libCppAddWrapper.a
g++ -c CppAddWrapper.cpp
ar -r libCppAddWrapper.a CppAddWrapper.o
C代码
main.c
#include "CppAddWrapper.h"
#include <stdio.h>
int main()
{
int sum = cppaddwrapper(1, 2);
printf("1+2 = %d\n", sum);
return 0;
}
编译main,同时指定libCppAdd.a 和 libCppAddWrapper.a
gcc -o main main.c -L. -lCppAddWrapper -lCppAdd
或者把libCppAdd.a合并到libCppAddWrapper.a中
ar -x libCppAdd.a # 提取CppAdd.o
ar -x libCppAddWrapper.a # 提取CppAddWrapper.o
ar -r libCppAddWrapper.a CppAdd.o CppAddWrapper.o # 打包libCppAddWrapper.a
gcc -o main main.c -L. -lCppAddWrapper # 只需要连接libCppAddWrapper.a即可
2.C++调用C
方法1:
- 在include的时候,要采用extern “C” 代码块形式.
- 为什么使用extern “C”?因为cpp支持了函数重载,在编译生成的汇编代码中,会对函数名字进行命名改编,并不是C语言中的简单的函数名而已。
C++代码
// add.h整个头文件中的所有函数都是分布在多个xxx.c文件中的, 因此肯定xxx.obj是按照Ccompiler规则编译, 函数名无改动,
// 那么, C++中引用头文件的时候, 要在外部加上extern "C"包裹, 表示说我知道这部分是
//采用Ccompiler规则的函数名, 我会采用这个规则去找函数;
#include <iostream>
extern "C" {
#include "add.h" // 由add.h和add.c组成
}
using namespace std;
int main() {
cout << addTwoNumber(10, 20) << endl;
system("pause");
return 0;
}
方法2:
// C Code
void foo( int x );
C++这样调用C函数
// C++ Code
extern "C" void foo( int x );
方法3:
C语言代码
CAdd.h
int cadd(int x, int y);
CAdd.c
#include "CAdd.h"
#include <stdio.h>
int cadd(int x, int y) {
printf("from C function.\n");
return (x + y);
}
编译libCAdd.a
gcc -c CAdd.c # 生成CAdd.o
ar -r libCAdd.a CAdd.o # 归档生成libCAdd.a
编译动态库 libCAdd.so
gcc -shared -o libCAdd.so CAdd.c
C++代码
#include <stdio.h>
extern "C" {
#include "CAdd.h"
}
int main()
{
int sum = cadd(1, 2);
printf("1+2 = %d\n", sum);
return 0;
}
编译main
-l指定库名称,优先链接so动态库,没有动态库再链接.a静态库。
g++ -o cppmain cppmain.cpp -L. -lCAdd
若找不到动态库的搜索路径,则:export LD_LIBRARY_PATH=./设置当前路径为系统链接库目录就可以了
方法4:
- 无论C还是C++直接正常include就可以使用了
#ifdef __cplusplus
extern "C" {
#endif
int cadd(int x, int y);
#ifdef __cplusplus
}
#endif
其他说明:
- 时常在cpp的代码之中看到这样的代码: 特别是C ++中引入C的头文件,这些C头文件中出现很多如下代码
- 其中__cplusplus是C++编译器的保留宏定义.就是说C++编译器认为这个宏已经定义了
- extern "C"是告诉C++编译器,连接的话按照C的命名规则去找
#ifdef __cplusplus extern "C"
{
#endif
//一段代码
#ifdef __cplusplus
}
#endif
- .so动态库、.a静态库和.o中间文件的关系
动态库链接和像静态库一样,告诉编译器函数的定义在这个库中;
静态或者动态库文件其实就是对.o中间文件进行的封装,使用nm libadd.a命令可以查看其中封装的中间文件以及函数符号;
链接静态库就是链接静态库中的.o文件(动态库类似),这和直接编译多个文件再链接成可执行文件一样; - 参考:如何用C语言封装 C++的类,在 C里面使用,C代码中如何调用C++ C++中如何调用C,C与C++代码如何互相调用,C调用C++库和C++调用C库的方法