如何将已编译的C代码与C++代码进行编译和链接?

6

我希望能够使用Cmockery来模拟被我测试的从C++调用的C函数。为了达到这个目的,我已将Cmockery示例run_tests.c重命名为run_tests.cpp,并尝试使用cmockery.c进行编译和链接:

g++ -m32 -DHAVE_CONFIG_H -DPIC -I ../cmockery-0.1.2 -I /usr/include/malloc -c run_tests.cpp -o obj/run_tests.o
gcc -m32 -DHAVE_CONFIG_H -DPIC -Wno-format -I ../cmockery-0.1.2 -I /usr/include/malloc -c ../cmockery-0.1.2/cmockery.c -o obj/cmockery.o
g++  -m32 -o run_tests obj/run_tests.o obj/cmockery.o

前两个命令行(编译)是成功的,但在最后一个命令行之后我收到了以下信息:

Undefined symbols:
  "_run_tests(UnitTest const*, unsigned long)", referenced from:
      _main in run_tests.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

那个未定义的符号来自于run_tests.cpp的第29行:
return run_tests(tests);

run_tests()函数定义在cmockery.c文件中。

阅读完“Linking C++ code with 'gcc' (without g++)”后,我尝试了以下操作:

gcc -lstdc++ -m32 -o run_tests obj/run_tests.o obj/cmockery.o

但是得到了相同的结果:
Undefined symbols:
  "_run_tests(UnitTest const*, unsigned long)", referenced from:
      _main in run_tests.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

我该如何编译和链接C++代码,以使其找到C代码中的符号?


在撰写本评论时,没有一个答案明确表明我不需要修改cmockery.h。我可以在run_tests.cpp中的#include <cmockery.h>周围放置extern "C"声明。我将接受第一个回答来澄清这一点。 - Daryl Spitzer
4个回答

7

我认为你可以通过在cmockery.h文件的内容周围添加以下内容来使C++链接到它:

在开头附近:

#if defined(__cplusplus)
extern "C" {
#endif

在或接近结尾处:

#if defined(__cplusplus)
}
#endif

那么,在C语言源代码中使用头文件时将忽略声明中的extern "C"部分,但是当头文件被包含在C++构建中时,编译器会正确地告知该头文件中的声明链接使用C语义。如果您想进行快速测试或者不想修改头文件,可以尝试:
extern "C" {
#include "cmockery.h"
}

但我的偏好是将 extern "C" 块放在头文件中(只包含必需内容 - 这可能需要一些分析)。


为什么您认为在#include周围加上extern"C"是"快速而肮脏"的做法? - Daryl Spitzer
一般情况下,由于它可能会将 extern "C" 修饰符应用于不需要它的内容(特别是如果头文件包含其他 C++ 感知的头文件),因此可能会出现问题。头文件可以通过使用 extern "C++" 声明规范来处理这个问题,但我只见过一次使用它来处理这种情况(可能是因为它很少被人知道,并且不像 extern "C" 版本那样经常需要)。 - Michael Burr

5

在您的C++代码包含的头文件中,对于所有编译为C的函数,您需要使用extern "C"声明。


2

当你在C++中包含C头文件时,是否已经使用extern "C" { .... }将原型包装起来了?如果没有,在链接时,C++函数名将被“修饰”。


2

正如Karl所说,需要使用extern "C" { .. }

原因是:C++会改变函数名(添加一些奇怪的字符),以确保链接是类型安全的。而C语言不会这样做,所以在该语言中将foo(int)链接到foo(double)是可能的(但是错误和令人尴尬的)。

为了成功地进行互操作性,您需要告诉C++编译器某些函数名不应被改变,以便链接成功。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接