在 C++ 中使用/混合 C代码?
在 C++ 中使用 C 不好吗?
许多人告诉我,在 C++ 中使用 C 不好,因为它不那么安全,并且需要更多的内存管理。我一直告诉他们,只要你知道自己在做什么,并且删除“new”并释放“malloc”,那么 C 就不是问题。
我目前在一个论坛上,正在就 std::string
与 char*
进行争论。有人说分配一个简单的 char* 内存块效率更高,只要释放它就可以了。另一方面,有人说 std::string 更优越,因为它不涉及内存管理,但效率较低。
所以这里的主要问题是:
- 混合 C/C++ 不好吗?当您编写 C++ 代码时,应该只使用 100% C++ 吗?
任何答案将不胜感激!
Is using C in C++ bad?
Many people have told me that using C in C++ is bad because it's not as safe, and it requires more memory management. I keep telling them that as long as you know what you're doing, and you delete your "new"s and free your "malloc"s then C isn't a problem.
I'm currently on a forum where an argument over std::string
vs. a char*
is taking place. Some people are saying that allocating a simple char*
memory block is more efficient, and as long as you deallocate it, it's fine. On the other hand we have people saying that std::string
is superior because it has no memory management involved but is less efficient.
So the main question here is:
- Is mixing C/C++ bad? Should you ONLY use 100% C++ when you're coding C++?
Any answers would be appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
这是真实的;如果您非常小心并确保手动清理东西,那么这不是问题。但你真的有时间这样做吗?每次调用
new
都会抛出std::bad_alloc
。您是否总是捕获每个可能抛出的异常并手动清理任何资源?我冒昧地猜测答案是“不”,因为编写这样的代码非常乏味,而且很难绝对确定这样编写的代码是正确的,即使在罕见的失败情况下也是如此。
如果答案是“是”,那么为什么要浪费这么多时间担心资源管理呢? C++ 惯用语(例如范围限制资源管理(SBRM;更常见的名称为资源获取即初始化 (RAII)))和标准模板库等库可帮助您更轻松地编写正确的代码。当你不需要的时候,为什么要以困难的方式去做事情呢?
是的,但是如果有一个 C 库可以完成您需要的操作,或者您有想要使用的遗留 C 代码,那么您当然可以使用该代码;请务必小心。通常,与 C 代码互操作的最简洁方法是围绕它编写 C++ 包装器。
This is true; if you are extraordinarily careful and ensure that you manually clean things up, then it isn't a problem. But do you really have the time to do that? Every call to
new
can throwstd::bad_alloc
. Do you always catch every exception that can be thrown and manually clean up any resources?I'd hazard to guess the answer to that is "no," because it is very tedious to write code like that and it is difficult to be absolutely sure that code written like that is correct, even in the case of rare failures.
If the answer is "yes," then why are you wasting so much time worrying about resource management? C++ idioms like scope-bound resource management (SBRM; more commonly known as resource acquisition is initialization (RAII)) and libraries like the standard template library are there to help you write correct code more easily. Why do things the hard way when you don't have to?
Yes, though if there is a C library that does something you need, or if you have legacy C code that you want to use, you can certainly use that code; just be sure to be careful. Often the cleanest way to interop with C code is to write a C++ wrapper around it.
我坚信您的问题根本与 C 或 C++ 无关。你的问题是用可疑的效率换取安全。是的,C 可以更高效。但效率有多高呢?你为此付出什么代价?这些是您应该回答的问题。在大多数情况下,字符串与 const char* 的开销是不明显的。如果您正在开发一个对效率极其关键的应用程序,那么为什么不首先用 C 语言对其进行编码呢?
My strong belief is that your question doesn't have to do with C or C++ at all. Your question is about trading dubious efficiency for safety. Yes, C can be more efficient. But how much more efficient? And what do you pay for that? These are the questions you should answer. In most cases string vs. const char* overhead is unnoticeable. If you are developing an efficiency-extremely-critical application, then why not code it in C in the first place?
我真的对答案和评论中的两极分化感到惊讶。
在我看来,答案很简单:
两个主要示例:
编写一个进行科学计算的 C++ 程序/库。我肯定会使用 GSL(GNU 科学库),它是用 C 编写的。只有一些警告(例如 GSL 中特定结构和函数的专门初始化和自由函数),可以在 std 中吸收::unique_ptr 类型定义。还有错误处理的问题:如果需要/想要,可以在异常机制中抽象检查错误代码,或者可以将错误代码保留在计算函数中。 GSL 确实有一种设置错误处理程序的方法,我想其他一些 C 库也有这样的功能。
使用 Win32 API 编写 C++ 程序,该程序完全基于 C。我说的是轻量级 API 使用,例如读取目录中的文件、检查文件是否存在等,而不是重度 GDI+ 或其他内容。我喜欢将 Win32 API 公开的所有 C 函数包装在漂亮的 C++ 风格函数中,也许有必要的例外,并返回
std::string
而不必传递char* buffer 作为参数。
我知道这两个例子都很……肤浅……但我觉得它们表达了一个足够普遍的想法。
I'm genuinely surprised by the polarization in the answers and comments thereof.
In my eyes, the answer is pretty simple:
Two prime examples:
Write a C++ program/library that does scientific calculations. I would definitely use GSL (GNU Scientific Library), and it is written in C. There are only a few caveats (like specialized initialize and free functions for specific structs and functions within GSL), that can be absorbed in a
std::unique_ptr
typedef. There is also the issue of error handling: checking error codes can be abstracted away in an exception mechanism if necessary/wanted, or you can keep the error codes contained within the calculation functions. GSL does have a way of setting up an error handler, I imagine some other C libraries have such a functionality.Writing a C++ program using the Win32 API, which is horribly C based. I'm talking about light API usage, like reading the files in a directory, checking if a file exists, etc., not heavy GDI+ or other stuff. I like to wrap all the C functions the Win32 API exposes in nice C++ style functions, perhaps with the necessary exceptions and returning a
std::string
instead of having to pass achar*
buffer as argument.I understand both examples are quite... shallow... but I feel they express a general enough idea.
是的,混合使用 C 和 C++ 是不好的,其原因与性能或安全性无关:
这是可维护性的不好原因:
因此,当您混合使用 C++ 和 C 时,您就打破了程序员对事物应如何工作的期望。
Yes it's bad to mix C and C++, and the reason has nothing to do with performance or security:
It is bad cause of a maintainability:
So when you mix C++ and C, you break both programmers expectations on how things should work.
答案当然是:这取决于情况。
一般来说,您希望避免混合可能导致混乱的东西,这可能进一步导致难以发现的错误。仅仅因为“你知道你在做什么”并不意味着下一个接触你代码的人会知道你在做什么。如果您正在开发只有您会使用的代码,那么可能没问题,但这种情况很少发生。
如果您小心的话,使用 C 来提高性能是没问题的。但只有当您知道自己需要性能时才应该这样做。过早的低级优化是魔鬼的工作。
在极少数情况下,使用 char* 而不是 std::string 会给您带来明显的性能优势,并且只有在确实如此的情况下才值得内存管理麻烦。
The answer is, of course: it depends.
Generally you want to avoid mixing things that can cause confusion, that can further lead to hard-to-find bugs. Just because "you know what your doing" doesn't mean that the next person to touch your code will know what you were doing. If you're developing code that only you will ever use, then it's probably okay, but that's rarely the case.
Using C for performance is fine if you're careful. But you should only do it if you KNOW that you need the performance. Premature low-level optimization is the work of the devil.
It's a very rare case where using char* over std::string will give you any noticeable performance benefits, and it's only worth the memory management hassle in those cases where it does for sure.
这里更好的问题是,为什么使用 C?表现?首先,我相信对于具有相同功能的程序来说,不存在可测量的性能差异。其次,您必须分析并证明对于您的具体情况,C++ 速度较慢。第三,使用 C 而不是 C++,您将放弃大量的应用程序安全性。
The better question here is, why use C? The performance? Firstly, I believe that there is no measurable performance difference for a program with the same function. Secondly, you would have to profile and prove that for your specific case, C++ is slower. Thirdly, you're giving up a huge quantity of application security by using C instead of C++.
关于
std::string
与char*
的争论:std::string
不会比char*< 慢/code> (对于堆
char*
);许多实现速度更快,因为它们使用私有内存池。无论如何,std::string 的稳健性远远超过任何(不太可能)的性能命中。Regarding the argument over
std::string
vschar*
:std::string
is not going to be slower thanchar*
(for heapchar*
); many implementations are much faster because they use private memory pool. And anyway the robustness ofstd::string
far outweighs any (unlikely) perf hit.这里简单的答案是,个人资料;确定哪种方式最适合您的情况并明智地使用它!
The simple answer here is, profile; determine which works best in your case and use it wisely!
虽然是一个主观问题:在我看来,采取很大措施避免在 C++ 程序中使用 C。
你正在重新引入 C++ 旨在克服的缺陷和危险,而这不是 C++ 程序中完成事情的方式。
我经常检查/拒绝/重写进入“具有 C++ 功能的 C”或“具有 C 功能的 C++”代码库的代码。我什至更改了 malloc、free 等以在根命名空间中进行断言(除其他外)。
在 C++ 中表示字符串的选项比 std::string 更多。
在我看来,创建一个代表字符串并服务于特定目的的新类是完全有效的,或者遵循附加合同(必要时)。当然,这种字符串表示形式的一部分契约是,当使用动态内存时,它们使用 new[]/delete[] 管理自己的资源。
如果效率如此重要,并且 std::string 对于特定任务来说不太理想,那么 C++ 就足够强大,可以通过在 C++ 中创建专门的接口来表达您对这些特定情况的意图。在很多情况下这是可以接受的(我认为),但并不总是值得投入时间。无论如何,它比将 c 惯用法/样式/危险集成到 c++ 程序中更容易管理。
最好根据您的需求创建可重用的基于对象的解决方案。所提供示例中的危险可以被完全封装(如果这种优化确实值得花时间投入),并使用 C++ 习惯用法进行编写,不会造成性能损失,并且具有更好的可维护性。
although a subjective question: in my opinion, take great measures to avoid using c in c++ programs.
you're reintroducing deficiencies and dangers c++ was designed to overcome, and it's not the way things are done in c++ programs.
i routinely check/reject/rewrite code that enters codebases that is "c with c++ features", or "c++ with c features". i even go as far as to change malloc, free, etc. to assert in root namespaces (among other things).
there are more options for representing a string in c++ than std::string.
in my opinion, it's completely valid to create a new class which represents a string and serves a particular purpose, or follows additional contracts (when necessary). part of the contracts of such string representations are (of course) that they manage their own resources using
new[]/delete[]
when dynamic memory is used.if efficiency is that important and
std::string
is less than ideal for a specific task, then c++ is powerful enough to express your intent for these specific cases by creating a specialized interface in c++. there are plenty of cases where this is acceptable (imo), but not always worth the time investment. in any event, it's easier to manage than integrating c idioms/styles/dangers into c++ programs.it's best to create reusable object based solutions for your needs. the dangers in the example provided can be completely encapsulated (if this optimization is truly worth the time investment), and be written to use c++ idioms, without performance loss and with better maintainability.
在
string
与const char *
的特定情况下,您应该对所有保存字符串常量的变量使用裸const char *
/em>(以及仅字符串常量),仅在传递到需要字符串
的 API 时才转换为字符串
。一致地这样做可以消除大量的全局构造函数,不会导致内存分配问题(因为字符串常量是永久的常量数据),并且 IMO 实际上使代码更清晰 - 你看const char *
,你知道这将是一个字符串常量。In the specific case of
string
versusconst char *
, you should use bareconst char *
for all variables that hold string constants (and only string constants), converting tostring
only when passing to an API that requiresstring
. Doing this consistently can eliminate enormous numbers of global constructors, does not cause memory allocation headaches (since string constants are permanent, constant data) and IMO actually makes the code clearer - you seeconst char *
, you know that's gonna be a string constant.如果你谈论的是技术,我会小心地说,执行上述操作是可以的。
使用 C 风格的程序组织技术编写 C++ 程序可能会导致许多可维护性问题。一般来说,程序员忽略了面向对象语言提供的许多好处。仅仅因为 C 语法的大部分是有效的 C++ 并且许多编码技术转移并不意味着您应该在 C++ 中执行它们。
也就是说,使用 C 函数和其他东西不是问题,只要你小心使用它们。在某些情况下,你必须这样做。
If your'e talking about techniques, I'd be careful to say that doing the above is okay.
Writing C++ programs using C-style program organization techniques will likely result in lots of maintainability issues. In general, the programmer is ignoring many of the benefits that an object-oriented language provides. Simply because much of C syntax is valid C++ and many coding techniques transfer does not mean you should do them in C++.
That said, using C functions and things isn't a problem, so long as your'e careful about their use. In some cases, you have to.
嗯,我的处境很奇怪。我正在开发一个应该使用 C++ 的系统(使用 C++ 编译器并使用术语 C++),但所有内容都是用 C 编写的。这非常令人沮丧,因为它已经到了我必须“证明”的地步' 尽管我们使用 C++ 进行编码,但 C++ 比 C 更好用。当我引入 std::string 时,一切都是地狱。我的看法是,现在一切都开始变得混乱(C 和 C++ 的混合)。错误处理的情况很少见。事实上,我想我可以数出 3 个系统范围的 try-catch 语句。代码混乱,内存泄漏突出,发现错误就像大海捞针一样。有数百行代码可以用C++函数替换。我想说编写代码更高效、更干净、更容易理解。
根据我的经验,当然可以混合使用 C 和 C++。您几乎可以做任何您想做的事情,但是维护、调试和实际弄清楚发生了什么就成了问题。说你要清理内存分配很容易,但也许其他人使用了你的代码但没有。也许您忘记这样做,并且浪费了几个小时来寻找愚蠢的错误,而不是利用这些时间来做一些富有成效的事情。我什至认为不应该有争论。当你做C++时,就做C++。当你做C的时候,就做C。
Well, I'm in a strange situation. I am working on a system that is supposed to be in C++ (C++ compiler is used and term C++ is used), but everything is written in C. This is very frustrating, because it is getting to a point where I have to 'prove' C++ is better to use than C, even though we are coding in C++. It was all hell when I introduced std::string. My take on it is that everything now is starting to get cluttered (mixing of C and C++). There are rare instances of error handling. In fact, I think I can count 3 system wide try-catch statements. The code is messy, memory leaks are prominent and finding an error is a needle in a haystack. There are hundreds of lines of code that can be replaced by C++ functions. I'd say writing the code is more efficient, cleaner and easier to understand.
From my experience, yes of course you can mix C and C++. You can pretty much do whatever you want, but maintaining, debugging and actually figuring out what's going on becomes a problem. It's easy to say you're going to clean-up your memory allocations, but maybe someone else uses your code and doesn't. Maybe you forget to do it and you waste hours on finding silly bugs, instead of using that time to do something productive. I don't even think there should be an argument. When you do C++, do C++. When you do C, do C.