C与CPP互相调用

0. 说明

  • C++采用g++编译,C采用gcc编译。两者主要不同点是:C++编译考虑到函数重载,会将原函数“改名”(命名倾轧name mangling);而在C中不存在重载,函数名不会变动。
  • g++和gcc可以兼容C++和C的编译方式,但是默认情况下g++采用C++编译方式;而gcc采用C的编译方式
  • 注意:gcc编译C++文件时不会主动链接C++用到的库stdc++,需要手动指定链接选项-lstdc++
  • __cplusplus宏定义会在编译cpp文件以及用C++的方式编译时被包含,因此用gcc编译.cpp文件或者g++编译.c、.cpp文件都会有这个宏
  • 之所以用条件判断,因为gcc不认识extern "C",直接编译会报错

1. C++调用C

只需要声明时包含extern "C"即可。下面的代码中,func.h可以不动,在main.cpp调用时,直接extern "C" int func(int, int)也是可以的。只需要让编译器按照C的方式编译,不要改动函数名即可正确链接的函数符号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// func.h 不论.c还是.cpp文件调用,都不会出错
#ifndef FUNC_H
#define FUNC_H

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

int func(int, int);

#ifdef __cplusplus
}
#endif // __cplusplus

#endif
1
2
3
4
5
6
// func.c
#include "func.h"

int func(int a, int b) {
return a + b;
}
1
2
3
4
5
6
7
// main.cpp
#include <iostream>
#include "func.h"

int main() {
std::cout << func(1, 3) << std::endl;
}

2. C调用C++

C调用C++稍微麻烦点,遇到类函数和重载函数往往需要嵌套一层,详细如下。

2.1. 普通函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// func.h
#ifndef FUNC_H
#define FUNC_H

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void func();

#ifdef __cplusplus
}
#endif

#endif

1
2
3
4
5
6
7
// func.cpp
#include "func.h"
#include <iostream>

void func() {
std::cout << "void func()" << std::endl;
}
1
2
3
4
5
6
// main.c
#include "func.h"

int main() {
func();
}

2.2. 重载函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// func.h
#ifndef ADAPTER_H
#define ADAPTER_H

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void func_();
void func_i(int);

#ifdef __cplusplus
}
#endif

#endif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// func.cpp
#include "func.h"
#include <iostream>

void func() {
std::cout << "void func()" << std::endl;
}

void func(int a) {
std::cout << "void func(int)" << std::endl;
}

// adapter
void func_() {
func();
}

void func_i(int a) {
func(a);
}
1
2
3
4
5
6
7
// main.c
#include "func.h"

int main() {
func_();
func_i(1);
}

2.3. 类函数

1
2
3
4
5
6
7
8
9
10
11
12
// Circle.h
#ifndef CIRCLE_H
#define CIRCLE_H

class Circle {
double radius;
public:
Circle(double r) :radius(r) {}
double getArea();
};

#endif
1
2
3
4
5
6
// Circle.cpp
#include "Circle.h"

double Circle::getArea() {
return 3.1415926 * radius * radius;
}

核心文件(adapter.h),此代码必须在C ++和C文件中都可以编译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// adapter.h
#ifndef ADAPTER_H
#define ADAPTER_H

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void* Circle_new(double);
double Circle_getAea(void*);
void Circle_detete(void*);

#ifdef __cplusplus
}
#endif

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// adapter.cpp
#include "adapter.h"
#include "Circle.h"

void* Circle_new(double r) {
Circle *p = new Circle(r);
return (void*)p;
}

double Circle_getAea(void* p) {
return ((Circle*)p)->getArea();
}

void Circle_detete(void* p) {
Circle* cp = (Circle*)p;
delete cp;
}
1
2
3
4
5
6
7
8
9
// main.c
#include <stdio.h>
#include "adapter.h"

int main() {
void* p = Circle_new(1);
printf("%lf\n", Circle_getAea(p));
Circle_detete(p);
}

3. 参考