没事造轮子没事造轮子

没事造轮子

C 和 C++ 混合编译

  • W_Z_C
  • 阅读约 2 分钟
C 和 C++ 混合编译

为了工作需要,在抽离一个开源库组件的时候,编译成功链接却失败,查找原因发现测试文件使用的是 C++语言,而库的组件使用的是 C语言,具体原因记录与此。

1. 现场

为了测试,写了一个单独的简单案例:

新建 win32 工程,建立三个文件,分别是 test.ctest.hmain.cpp

#include "test.h"

int main()
{
	test(1);
	return 0;
}

编译运行:

编译结果

2. 原因

编译成功,链接失败,很显然代码中已经实现了 test 函数,为了查找原因,直接打开 vs 命令行工具查看一下编译后的符号表都有什么。

进入 Debug 目录,执行 dumpbin /SYMBOLS test.obj

test.c 符号表

答案很显然,编译 test.c 生成的符号是 _test,而现在要找的是 void __cdecl test(int)" (?test@@YAXH@Z),结果当然是无法找到的。

为了进一步确认答案,将 test.c 改为 test.cpp,重新编译,查看符号表。

test.cpp 符号表

对于 C语言生成的符号表和 C++语言生成的符号表差距很大,原因无非是 C++ 支持了很多新的功能,原来的符号表生成规则已经无法满足。

例如:重载、多态等机制。

为了解决这个问题,C++ 语言引入了另一种语法来解决这个问题。

C++ 标准文档语法描述

3. 结论

对于 C语言编写的程序来说,未来可能被 C语言或者 C++ 语言的用户所使用,大部分解决的方法是:

#ifdef __cplusplus
extern "C" {
#endif

// ...

#ifdef __cplusplus
}
#endif

这样做的原因有两个,用 #ifdef 条件语句包裹是因为这种语法对于 C语言自身是语法错误,对于 C语言调用 C语言的函数根本不会存在这个问题,它的目标是使用 C++ 语言的用户,C++ 语言中支持该语法并且在调用 C语言的函数的时候是必须的,原因如上所述。