文章

在GCC环境中开发C和C++混合项目

代码

假设我们有一个用 C++实现的“b 模块”,和 C 语言实现的“a 模块”。我们希望用 a 模块调用 b 模块,也就是 C 调用 C++。

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

void testfunc(int arg){
    std::cout << "testfunc:"<< arg << std::endl;
    return;
}

首先我们需要给 b 模块写一个 C 语言能够识别的接口,由于 C++中存在命名空间的概念,所以每个函数在编译后的符号名字会有前缀用以表明命名空间,和 C 中的定义不同,此时 C 将无法通过函数名找到对应的符号。可以通过extern "C"的方式将其声明为兼容 C 的接口:

1
2
3
4
5
6
7
8
9
10
// b.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif

void testfunc(int arg);
#ifdef __cplusplus
}
#endif

另一种写法:

1
2
3
4
5
6
7
8
9
// b.h
#pragma once
#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN extern
#endif

EXTERN void testfunc(int arg);

之后可以在 a 模块中直接调用该函数:

1
2
3
4
5
6
7
8
// a.c
#include "b.h"

int main(int argc, char *argv[])
{
    testfunc(3);
    return 0;
}

使用 C++ 调用 C 语言模块也是同理。

编译链接

1
2
3
PS /> g++ -c b.cpp
PS /> gcc -c a.c
PS /> g++ a.o b.o -o test.exe

使用 g++ 编译 cpp,用 gcc 编译 c,得到中间文件,之后必须要使用 g++ 作为链接器完成链接。

如果使用 cmake 这个过程会更加简单,cmake 会根据文件的后缀名自动选择使用 gcc 还是 g++ 编译,链接时也会自动识别项目中是否包含 c++ ,从而自动选中 g++ 或 gcc 作为链接器:

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 3.18)

project(test)

set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)

add_executable(test a.c b.cpp)
1
2
3
PS /> cd build
PS /> cmake -G "Unix Makefiles" ..
PS /> make

执行结果

1
2
PS /> .\test.exe
testfunc:3

可以看到 C++ 函数被正常调用,且参数传递也正确。

本文由作者按照 CC BY 4.0 进行授权

© Kai. 保留部分权利。

浙ICP备20006745号-2,本站由 Jekyll 生成,采用 Chirpy 主题。