使用 C++ 编译器编译 C 代码会出现什么问题?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/861517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:38:22  来源:igfitidea点击:

What issues can I expect compiling C code with a C++ compiler?

c++ccompiler-constructionmigrationlanguage-interoperability

提问by Chris Arguin

If you take an existing C code base and compile it with a C++ compiler, what sort of issues can you expect to crop up? For example, I think that assigning an integer to an value with an enumerated type will fail in C++, whereas it's legal (if a bit nasty) in C.

如果您使用现有的 C 代码库并使用 C++ 编译器对其进行编译,您预计会出现什么样的问题?例如,我认为将整数分配给枚举类型的值在 C++ 中会失败,而在 C 中它是合法的(如果有点讨厌)。

If I don't wrap all my C files in extern C { ... }, am I going to get name-mangling where I least expect it? Is there some reason why I really shouldn't do this?

如果我不将所有 C 文件都包含在extern C { ... }. 有什么理由让我真的不应该这样做吗?

For background, we have a very large code-base written in C. For a few years we've been jumping through hoops to do things that would come naturally via C++ ( homebrewe inheritance, for example). We'd like to start moving towards C++, but in a gradual fashion; getting our CORBA-like framework to support it, and refactoring modules as we go along to take advantage of the more natural approach C++ would provide.

作为背景,我们有一个非常大的用 C 编写的代码库。几年来,我们一直在跳槽来做一些可以通过 C++ 自然实现的事情(例如自制继承)。我们想开始转向 C++,但要循序渐进;让我们的类似 CORBA 的框架支持它,并在我们继续使用 C++ 提供的更自然的方法时重构模块。

采纳答案by Ville Laurikari

I've done something like this once. The main source of problems was that C++ is more strict about types, as you suspected. You'll have to add casts where void* are mixed with pointers of other types. Like allocating memory:

我曾经做过这样的事情。正如您所怀疑的,问题的主要来源是 C++ 对类型更严格。您必须在 void* 与其他类型的指针混合的地方添加强制转换。比如分配内存:

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

The above is typical C code, but it'll need a cast in C++:

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

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

There are new reserved words in C++, such as "class", "and", "bool", "catch", "delete", "explicit", "mutable", "namespace", "new", "operator", "or", "private", "protected", "friend", etc. These cannot be used as variable names, for example.

C++中有新的保留字,如“class”、“and”、“bool”、“catch”、“delete”、“explicit”、“mutable”、“namespace”、“new”、“operator”、 “or”、“private”、“protected”、“friend”等。例如,这些不能用作变量名。

The above are probably the most common problems when you compile old C code with a C++ compiler. For a complete list of incompatibilities, see Incompatibilities Between ISO C and ISO C++.

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

You also ask about name mangling. In absence of extern "C" wrappers, the C++ compiler willmangle the symbols. It's not a problem as long as you use onlya C++ compiler, and don't rely on dlsym() or something like that to pull symbols from libraries.

您还询问了名称修改。在没有 extern "C" 包装器的情况下,C++ 编译器破坏符号。只要您使用 C++ 编译器,并且不依赖 dlsym() 或类似的东西从库中提取符号,这不是问题。

回答by Adam Rosenfield

See Incompatibilities between ISO C and ISO C++for a verydetailed list of all of the incompatibilities. There are a lot of subtle issues, including some which don't immediately manifest in a compiler error. For example, one issue that can be a problem is the size of character constants:

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

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

回答by Steve Jessop

If I don't wrap all my C files in "extern C { ... }", am I going to get name-mangling where I least expect it?

如果我不将所有 C 文件都包装在“extern C { ... }”中,我是否会在我最不期望的地方进行名称修改?

It bites you when you try to link together C and C++.

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

I've written a lot of header files containing:

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

#ifdef __cplusplus
    extern "C" {
#endif

// rest of file

#ifdef __cplusplus
    }
#endif

After a while it merges into the existing multiple-include boilerplate and you stop seeing it. But you do have to be careful where you put it - usually it belongs afterany includes your header does.

一段时间后,它合并到现有的多包含样板中,您就不再看到它了。但是你必须小心你把它放在哪里 - 通常它属于任何包含你的标题之后

Is there some reason why I really shouldn't do this?

有什么理由让我真的不应该这样做吗?

If you know for sure you aren't going to combine C and C++ then there's no reason to do it that I know of. But with the gradual migration you describe, it's essential for anything with a published interface that both C components and C++ components need to use.

如果您确定不会将 C 和 C++ 结合起来,那么我所知道的就没有理由这样做。但是随着您描述的逐步迁移,对于具有 C 组件和 C++ 组件都需要使用的已发布接口的任何东西来说,它都是必不可少的。

The big reason notto do it is that it prevents you from overloading functions (at least, in those headers). You might find you want to do that once you've migrated all your code to C++ and started maintaining/refactoring/extending it.

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

回答by Graham Asher

In general, you won't get any problems at all. Yes, there are some incompatibilities between C and C++, but they don't seem to come up that often except for the malloc casting mentioned above, which is pretty trivial to fix.

一般来说,你根本不会遇到任何问题。是的,C 和 C++ 之间存在一些不兼容,但它们似乎并不经常出现,除了上面提到的 malloc 转换,这是很容易修复的。

I have successfully compiled and used the following open-source C libraries as C++:

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

  • the Expat XML parser
  • the FreeType2 font rasterizer
  • libjpeg: handles JPEG images
  • libpng: handles PNG images
  • the Zlib compression library
  • Expat XML 解析器
  • FreeType2 字体光栅化器
  • libjpeg:处理 JPEG 图像
  • libpng:处理 PNG 图像
  • Zlib 压缩库

The hardest part was adding namespace wrappers, which took some hours, largely because of #include statements buried deep in the code, which had to be outside the C++ namespace.

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

Why did I do this? Because I sell a commercial library which people were linking directly into their apps; and sometimes their apps were linked to other versions of Expat, FreeType, etc. This caused multiply-defined-symbol errors. The cleanest thing to do was to move everything inside my library and hide it in my namespace.

我为什么这样做?因为我出售一个商业图书馆,人们直接将其链接到他们的应用程序中;有时他们的应用程序会链接到其他版本的 Expat、FreeType 等。这会导致多重定义符号错误。最干净的做法是将所有内容移动到我的库中并将其隐藏在我的命名空间中。

However, I didn't do that with all the open-source libraries I use. Some haven't caused conflicts yet, and I haven't got round to fixing them, which although trouble-free is quite tedious. The interesting exception is SQLite, which I couldn't get to compile in C++. So I did a massive search and replace, adding a prefix (the name of my product) to every single externally visible symbol. That solved my client's problem.

但是,我并没有对我使用的所有开源库都这样做。有些还没有引起冲突,我还没有时间修复它们,虽然无故障是很乏味的。有趣的例外是 SQLite,我无法用 C++ 编译它。因此,我进行了大量搜索和替换,为每个外部可见符号添加了前缀(我的产品名称)。这解决了我客户的问题。

回答by piotr

Another example: there's not an implicit conversion from ints to enums in C++, while there's one in C. You'll need a cast if you really want to do it in C++.

另一个例子:在 C++ 中没有从整数到枚举的隐式转换,而在 C 中有一个。如果你真的想在 C++ 中进行转换,你将需要一个转换。

回答by paulm

I've done this before using MSVC, if using MSVC a good strategy is:

我在使用 MSVC 之前已经这样做了,如果使用 MSVC,一个好的策略是:

  1. Set individual files to build as CPP, that way you can incrementally move to a CPP compiler.
  2. Work through file by file using ctrl+f7 just to build that one file.
  3. Rather than casting all mallocs you can create a template version instead
  1. 将单个文件设置为 CPP,这样您就可以逐步迁移到 CPP 编译器。
  2. 使用 ctrl+f7 逐个文件地工作以构建该文件。
  3. 您可以创建一个模板版本,而不是强制转换所有 malloc

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

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

becomes

变成

foo = malloc<Foo>();

And of course you can have an overload for the cases where you want a Foo+n bytes

当然,对于需要 Foo+n 字节的情况,您可以重载

I'd also recomment switching the memory allocations to use RAII where possible too, I found that some functions where pretty complex so switching to RAII was too high risk, for the most case it was simple enough to do.

我还建议尽可能将内存分配切换为使用 RAII,我发现某些功能非常复杂,因此切换到 RAII 的风险太高,在大多数情况下,这很简单。

回答by user253751

C++ has stricter type checking, so you might need to add a cast to each call to malloc/realloc/calloc.

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

回答by Dimitrie D.

try to compile with a C++ compiler:

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

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