使用 C++ 编译 C 代码会出现什么问题? 编译器?
如果您采用现有的 C 代码库并使用 C++ 编译器对其进行编译,预计会出现什么类型的问题? 例如,我认为在 C++ 中将整数分配给枚举类型的值会失败,而在 C 中这是合法的(如果有点讨厌)。
如果我不将所有 C 文件包装在 extern C { ... },我会在我最意想不到的地方遇到名称修改吗? 有什么理由让我真的不应该这样做吗?
作为背景,我们有一个用 C 编写的非常大的代码库。几年来,我们一直在努力做一些通过 C++ 自然实现的事情(例如自制继承)。 我们希望开始转向 C++,但要循序渐进; 让我们的类似 CORBA 的框架来支持它,并重构模块,以利用 C++ 提供的更自然的方法。
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.
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?
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
如果我不将所有 C 文件包装在“extern C { ... }”中,我是否会在我最意想不到的地方遇到名称修改?
当您尝试链接时,它会咬住您C 和 C++ 一起。
我已经编写了很多头文件,其中包含:
一段时间后,它合并到现有的多重包含样板中,您将不再看到它。 但您必须小心放置它的位置 - 通常它位于之后任何包含您的标头的位置。
有什么理由让我真的不应该这样做吗?
如果您确定不会将 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?
It bites you when you try to link together C and C++.
I've written a lot of header files containing:
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 after any 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.
The big reason not to 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 和 C++ 之间存在一些不兼容性,但除了上面提到的 malloc 转换之外,它们似乎并不经常出现,修复起来非常简单。
我已成功编译并使用以下开源 C 库作为 C++:
最困难的部分是添加命名空间包装器,这需要几个小时,很大程度上是因为 #include 语句深埋在代码中,而这些语句必须位于 C++ 命名空间之外。
我为什么这么做? 因为我出售一个商业图书馆,人们可以直接链接到他们的应用程序; 有时他们的应用程序会链接到其他版本的 Expat、FreeType 等。这会导致多重定义符号错误。 最干净的做法是将所有内容移至我的库中并将其隐藏在我的命名空间中。
然而,我并没有对我使用的所有开源库都这样做。 有些还没有引起冲突,我也没有时间去解决它们,虽然没有麻烦,但相当乏味。 有趣的例外是 SQLite,我无法用 C++ 对其进行编译。 因此,我进行了大量搜索和替换,为每个外部可见的符号添加了前缀(我的产品名称)。 这解决了我客户的问题。
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.
I have successfully compiled and used the following open-source C libraries as C++:
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.
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.
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.
另一个例子:C++ 中没有从整数到枚举的隐式转换,而 C 中有一个。如果您确实想在 C++ 中执行此操作,则需要进行强制转换。
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++.
我在使用 MSVC 之前已经这样做过,如果使用 MSVC,一个好的策略是:
当然
,在需要 Foo+n 字节的情况下,您可能会出现重载,
我还建议在可能的情况下将内存分配切换为使用 RAII,我发现某些函数非常复杂,因此切换到 RAII 也太麻烦了高风险,在大多数情况下,这很简单。
I've done this before using MSVC, if using MSVC a good strategy is:
becomes
And of course you can have an overload for the cases where you want a Foo+n bytes
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.
C++ 具有更严格的类型检查,因此您可能需要为每次调用 malloc/realloc/calloc 添加强制转换。
C++ has stricter type checking, so you might need to add a cast to each call to malloc/realloc/calloc.
尝试使用 C++ 编译器进行编译:
try to compile with a C++ compiler:
我曾经做过一次这样的事情。 正如您所怀疑的,问题的主要根源是 C++ 对类型更加严格。 您必须在 void* 与其他类型的指针混合的情况下添加强制转换。 就像分配内存一样:
上面是典型的 C 代码,但在 C++ 中需要进行强制转换:
C++ 中有新的保留字,例如“class”、“and”、“bool”、“catch”、“delete” 、“explicit”、“mutable”、“namespace”、“new”、“operator”、“or”、“private”、“protected”、“friend”等。例如,这些不能用作变量名称。
以上可能是使用 C++ 编译器编译旧 C 代码时最常见的问题。 有关不兼容性的完整列表,请参阅ISO C 和 ISO C++ 之间的不兼容性。
您还询问有关名称修改的问题。 如果没有 extern“C”包装器,C++ 编译器将破坏符号。 只要您仅使用 C++ 编译器,并且不依赖 dlsym() 或类似的东西从库中提取符号,这就不成问题。
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:
The above is typical C code, but it'll need a cast in C++:
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.
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++.
You also ask about name mangling. In absence of extern "C" wrappers, the C++ compiler will mangle the symbols. It's not a problem as long as you use only a C++ compiler, and don't rely on dlsym() or something like that to pull symbols from libraries.
请参阅ISO C 和 ISO C++ 之间的不兼容性了解非常的详细信息所有不兼容性的列表。 有很多微妙的问题,包括一些不会立即在编译器错误中显现出来的问题。 例如,一个可能成为问题的问题是字符常量的大小:
See Incompatibilities between ISO C and ISO C++ for a very detailed 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: