【问题标题】:How do I compile and link C++ code with compiled C code?如何编译 C++ 代码并将其与已编译的 C 代码链接?
【发布时间】:2011-06-03 15:42:59
【问题描述】:

我希望能够使用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。我可以将extern "C" 声明放在run_tests.cpp 中的#include <cmockery.h> 周围。我会接受第一个答案来说明这一点。

标签: c++ c gcc undefined-symbol cmockery


【解决方案1】:

我认为您可以通过在 cmockery.h 文件的内容周围添加以下内容来让 thinkgs 从 C++ 链接:

在或接近开头:

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

在或接近尾声:

#if defined(__cplusplus)
}
#endif

这样,在 C 源代码中使用标头将忽略声明的 extern "C" 部分,但是当标头包含在 C++ 构建中时,编译器将被正确告知该标头中声明的链接使用C 语义。

对于快速-n-dirty 测试或者如果您不想修改标头,您可以尝试:

extern "C" {
#include "cmockery.h"
}

但我的偏好是将extern "C" 块放在标题中(并且只在需要的东西周围 - 这可能需要一些分析)。

【讨论】:

  • 为什么要考虑将extern "C" 放在#include “quick-n-dirty”周围?
  • 在一般情况下,因为它可能会将 extern "C" 修饰符应用于不期望它的内容(特别是如果标头包含其他可识别 C++ 的标头)。标头可以通过使用extern "C++" 声明规范来处理这个问题,但我只见过一次用于处理这种情况(可能是因为它鲜为人知,而且它不像extern "C" 版本那样需要)。跨度>
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    当您包含来自 C++ 的 C 头文件时,您是否使用 extern "C" { .... } 包装了原型?如果您不这样做,C++ 函数名称将在链接时被“损坏”。

    【讨论】:

      【解决方案4】:

      正如 Karl 所说,extern "C" { .. } 是必需的。

      原因:C++ 破坏了名称(添加了有趣的字符),因此链接是类型安全的。 C 没有,所以在那种语言中将foo(int) 链接到foo(double) 是可能的(但错误且令人尴尬)。

      为了成功的互操作性,您需要告诉 C++ 编译器某些函数名称不能被破坏,以便链接成功。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 1970-01-01
        • 2012-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多