如何使用 C++ link 带有保留关键字的旧 C 代码?

How to link old C code with reserved keywords in it with C++?

我有一个 10 多年历史的 C 库——我相信——在过去的美好时光里它工作得很好,但是当我尝试将它与 C++ 源代码(包含主函数)一起使用时,有一天我 运行 遇到了一些困难。

编辑:澄清一下,C 库在 gcc 下编译得很好,它会生成一个目标文件 old_c_library.o。这个库 was 应该以某种方式使用,以便 C 头文件 old_c_library.h 在您的 main.c C 源文件中 #included。然后你的主 C 源文件应该被编译并通过 gccold_c_library.o 链接在一起。在这里,我想使用 C++ 源文件 main.cpp,并且 compile/link 它与 g++.

在编译C++源文件的过程中出现了以下三个问题:

  1. 其中一个C库的头文件中含有C++保留字new(整数名),导致致命错误;和
  2. C 库的一个头文件包含 calloc 调用(缺少显式类型转换),导致致命错误;和
  3. C 库的各种文件包含有符号和无符号整数比较的代码,这会导致警告。

编辑:我尝试按照评论中的建议使用 #extern "C" { #include "obsolete_c_library.h" } "trick",但这并没有解决我的任何问题。

我可以通过重命名保留字的所有实例并将它们替换为 - 基本上 - 任何其他内容来解决问题 1。我可以通过对 calloc 调用进行类型转换来解决问题 2。我可能会尝试按照此处建议的想法来整理警告:How to disable GCC warnings for a few lines of code.

但我仍然想知道,是否有一种优雅、高级的方式来克服这些困难,而不实际接触原始库?


相关: Where is C not a subset of C++? and Do I cast the result of malloc? and How do I use extern to share variables between source files?.

  1. 你可以写一个 c header 的副本,唯一的区别是缺少 extern int new 的声明。然后使用新创建的 c++ 友好 header 而不是旧的、不兼容的

    如果您需要从 C++ 中引用该变量,那么您需要做一些更复杂的事情。您将需要用 c 编写一个新的包装器库,它公开 读写函数 一个指向 c++ 的指针,可用于访问不幸命名的变量。

    如果某些内联函数引用该变量,那么您可以将它们从重复的 header 中删除,如果您需要从 c++ 调用它们,re-implement 它们将以 c++ 友好的方式调用。只是不要在 extern "C" 中给 re-implementation 相同的名称,因为这会使您与某些现有 c 代码可能使用的原始内联函数发生冲突。

  2. 按照 1. 中所述进行相同的 header 复制。省略有问题的内联函数,并在需要时 re-implementing。

  3. 如您所知,可以忽略或禁用警告。无需修改原来的headers。您可以使用不生成警告的版本重写任何 {const,type} 不安全的内联函数,但您必须考虑您的时间是否值得。

这种方法的缺点是您现在有两个版本的 some/all 和 header。 c++用到的新的,一些旧代码可能用到的旧的。


如果您可以放弃不接触原始库的要求并且不需要使用现有的编译二进制文件,那么一个优雅的解决方案是简单地重命名有问题的变量 (1.)。制作 non-c++ 兼容的内联函数 (2.) non-inline 并将它们移动到 c 源文件中。修复生成警告的不安全代码 (3.),或者如果警告是特定于 C++ 的,只需使函数 non-inline.

一般来说,将 #include C header 文件转换为 C++ 源代码是不安全的,如果这些 header 文件不是为此类使用而构建的。在某些情况下它可以工作,但您需要准备好修改 header 或为您要访问的函数和全局变量编写您自己的声明。

至少,如果 C header 声明了任何函数并且您没有在 C++ 中重新编译这些函数,那么您必须确保在 C++ 代码中为声明分配了 C 链接。 C headers 通过条件编译指令自动解决这个问题并不少见,但如果它们不这样做,那么你可以在另一端通过将包含包含在 C 链接块中来做到这一点:

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

如果 C header 声明的全局变量的名称与 C++ 关键字冲突,并且您不需要引用,那么您可能可以使用预处理器重新定义它们:

#define new extern_new
#include "myclib.h"
#undef  new

这不能保证一定有效,但值得一试。不要忘记在包含 C header 之后 #undef 这样的宏,如图所示。

可能还有其他有趣的技巧,您可以使用宏来调整特定的 headers 以适应 C++,但在某些时候,只复制/重写所需的声明(并且只复制/重写那些声明)更有意义,在您的主要 C++ 源代码或您自己的 C++ header 中。请注意,这样做并不能消除声明 C 链接的需要——该要求来自由 C 编译器而不是 C++ 编译器编译的库。