我可以期望用C ++编译器编译C代码有哪些问题?

如果您使用现有的C代码库并使用C ++编译器进行编译,那么您可能会期望出现什么样的问题? 例如,我认为给一个枚举types的值赋一个整数将会在C ++中失败,而在C中它是合法的(如果有点讨厌的话)。

如果我不把所有的C文件都包含在extern C { ... } ,我会在最不经意的地方得到名字吗? 我有什么理由不这样做?

对于后台,我们有一个用C编写的非常大的代码库。几年来,我们一直在通过C ++(例如homebreweinheritance)自然而然地完成一些事情。 我们想要开始朝着C ++方向发展,但是要逐步推进。 让我们的类似CORBA的框架支持它,并重构模块,以便利用C ++提供的更自然的方法。

我曾经做过这样的事情。 问题的主要来源是C ++对types更为严格,正如您所怀疑的那样。 你必须在void *和其他types的指针混合在一起。 像分配内存一样:

 Foo *foo; foo = malloc(sizeof(*foo)); 

以上是典型的C代码,但它需要在C ++中进行强制转换:

 Foo *foo; foo = (Foo*)malloc(sizeof(*foo)); 

在C ++中有新的保留字,例如“class”,“and”,“bool”,“catch”,“delete”,“explicit”,“mutable”,“namespace”,“new”,“operator” “或”,“私人”,“受保护”,“朋友”等。这些不能用作variables名称。

以上是使用C ++编译器编译旧C代码时最常见的问题。 有关不兼容性的完整列表,请参阅ISO C与ISO C ++之间的不兼容性。

你也会问一些关于名字的问题。 如果没有外部“C”包装,C ++编译器将会破坏这些符号。 只要你使用一个C ++编译器,不要依赖dlsym()或类似的东西来从库中提取符号。

有关所有不兼容性的详细列表,请参阅ISO C和ISO C ++之间的不兼容性。 有很多微妙的问题,包括一些不能立即在编译器错误中出现的问题。 例如,一个可能成为问题的问题是字符常量的大小:

 // In C, prints 4. In C++, prints 1 printf("%d\n", sizeof('A')); 

如果我不把所有的C文件都包含在“extern C {…}”中,我会在最不经意的地方得到名字吗?

当你尝试将C和C ++连接在一起时,它会咬你。

我写了很多头文件,其中包含:

 #ifdef __cplusplus extern "C" { #endif // rest of file #ifdef __cplusplus } #endif 

一段时间后,它融入现有的多包装样板,你不再看到它。 但是,你必须小心你的位置 – 通常它属于任何包括你的标题之后

我有什么理由不这样做?

如果你确实知道你不打算把C和C ++结合起来,那么我就没有理由这样做。 但是随着你所描述的渐进式迁移,对于C和C ++组件都需要使用的发布接口来说,这是非常重要的。

这样做的最大原因是它阻止了你重载函数(至less在这些头文件中)。 一旦将所有代码迁移到C ++并开始维护/重构/扩展它,您可能会发现您想要这样做。

另一个例子:在C ++中没有从int到enums的隐式转换,而在C中有一个。如果你真的想用C ++来完成,你需要一个转换。

我在使用MSVC之前已经完成了这个工作,如果使用MSVC,一个好的策略是:

  1. 将单个文件设置为CPP,这样您可以递增地移动到CPP编译器。
  2. 使用ctrl + f7逐个文件地构build一个文件。
  3. 而不是投射所有的malloc,你可以创build一个模板版本

foo =(Foo *)malloc(sizeof(* foo));

 foo = malloc<Foo>(); 

当然,如果你想要一个Foo + n个字节的话,你可以有一个重载

我也build议切换内存分配,以便在可能的情况下使用RAII,但是我发现一些function非常复杂,因此切换到RAII的风险太高,大多数情况下很简单。

C ++具有更严格的types检查,因此您可能需要为每个调用malloc / realloc / calloc添加一个强制转换。

一般来说,你不会有任何问题。 是的,C和C ++之间有一些不兼容的地方,但是除了上面提到的malloc转换之外,它们似乎并没有经常出现,这是非常微不足道的。

我已经成功地编译并使用了以下开源C库作为C ++:

  • Expat XMLparsing器
  • FreeType2字体光栅化器
  • libjpeg:处理JPEG图像
  • libpng:处理PNG图像
  • Zlib压缩库

最难的部分是添加命名空间包装器,这需要几个小时,主要是因为#include语句埋在代码深处,必须在C ++名称空间之外。

我为什么要这样做? 因为我出售一个商业图书馆,人们直接链接到他们的应用程序; 有时他们的应用程序被链接到其他版本的Expat,FreeType等,这导致了多重定义的符号错误。 最干净的事情是把我的库里面的所有东西都移到我的名字空间里。

但是,我没有使用所有的开源库。 有些还没有引起冲突,我也没有去纠正,虽然没有问题,但是相当繁琐。 有趣的例外是SQLite,我不能用C ++编译。 所以我做了大量的search和replace,为每个外部可见的符号添加一个前缀(我的产品的名称)。 这解决了我的客户的问题。

尝试用C ++编译器进行编译:

 typedef enum{ false = 0, true = 1} bool;