我没有看到任何理由,除了个人不喜欢,甚至为编程嵌入式系统和类似的事情。在 C + + 中,你只为你使用的特性支付额外费用。在某些特定的情况下,您可以使用 C + + 的 C 子集,因为 C + + 的开销对您来说太高了。这就是说,我认为一些 C 程序员高估了一些 C + + 构造的开销。让我列举一些例子:
与普通函数相比,类和成员函数的开销为零(除非使用虚函数,在这种情况下,与使用函数指针相比没有开销)
模板的开销非常小(通常根本没有开销)
一个合理的原因是,当你为一个平台编程时,没有一个像样的 C + + 编译器(根本没有 C + + 编译器,或者编译器存在,但是实现很差,并且为一些 C + + 特性带来了不必要的高额开销)。
我从来没有看到任何关于使用 C 而不是 C + + 的争论,我认为这是令人信服的。我认为大多数人害怕 C + + 提供的某些特性,这是有道理的。然而,这并不能说服我,因为我们可以通过编码标准来强制是否使用某些特性。即使是 C 语言,也有很多你想要避免的东西。完全摒弃 C + + 实质上是说它没有提供比 C 更实际的好处来帮助人们编写更好的代码,我认为这种观点相当无知。
此外,人们似乎总是提出没有 C + + 编译器的平台的情况。当然 C 在这里是合适的,但我认为现在很难找到这样的平台。
C + + 的学习曲线要长得多。C 只有很少的结构,你需要知道,然后你可以开始编码强大的软件。在 c + + 中,你需要学习 C 基础,然后是面向对象和泛型,例外等等。过了一段时间,你可能已经知道了大部分的特性,并且可以使用它们,但是你仍然不知道编译器将如何翻译它们,它们是否有隐式的开销。这需要花费大量的时间和精力。
对于一个专业项目来说,这个论点可能不算数,因为你可以雇佣那些已经非常熟悉 C + + 的人。但是在开源项目中,C 仍然被广泛使用,人们选择他们喜欢的语言并且他们能够使用。考虑到并不是每个操作系统程序员都是专业的程序员。
我知道这既不是一个专业的答案,也不是一个特别好的答案,但对我来说,这只是因为我真的喜欢 C 语言小巧而简单,我可以把整个语言放在我的大脑里,C + + 对我来说总是看起来像一个巨大的混乱,有各种各样的层,我很难理解。正因为如此,我发现无论何时我写 C + + ,我都会花费比编写 C 时更多的时间在调试和撞击硬表面上。我再次意识到,这很大程度上是我自己“无知”的结果。
如果我可以选择,我会写所有高级的东西,比如 Python (或者可能是 C #)中的接口和数据库交互,以及所有在 C 语言中必须快速的东西,对我来说,这是所有世界中最好的。用 C + + 编写所有的东西感觉就像是得到了世界上最糟糕的东西。
编辑:
我想补充的是,我认为如果你要几个人一起做一个项目,或者如果可维护性是优先考虑的,那么使用一些 C + + 特性在很大程度上是一个坏主意。关于什么构成了一个“少数”,哪些比特应该在 C 中完成,哪些比特应该在 C + + 中完成,最终会导致一个非常精神分裂的代码库,人们将会有分歧。
缺乏支持——不是每个 C 编译器都是 C + + 编译器。并非所有的编译器都特别符合标准,即使它们声称支持 C + + 。而且一些 C + + 编译器生成的代码臃肿得无可救药,效率低下。有些编译器对标准库的实现很糟糕。内核模式开发通常不可能使用 C++标准程式库,以及一些语言特性。如果你坚持使用 C + + 语言的核心,你仍然可以编写 C + + 代码,但是那样切换到 C 语言可能会更简单。
Familiarity. C++ is a complex language. It's easier to teach someone C than C++, and it's easier to find a good C programmer than a good C++ programmer. (keyword here is "good". There are plenty of C++ programmers, but most of them have not learned the language properly)
学习曲线-如上所述,教人 C + + 是一个巨大的任务。如果你正在编写一个将来必须由其他人维护的应用程序,而这些人可能不是 C + + 程序员,那么用 C 语言编写它会使你更容易掌握它。
如果可以的话,我还是更喜欢用 C + + 编写,总的来说,我认为利大于弊。但我也看到了在某些情况下使用 C 的论点。
我想跟进丹 · 奥尔森的回答。我相信人们害怕 C + + 潜在的危险和适得其反的特性,这是有道理的。但与丹所说的不同,我不认为简单地决定一个编码标准是有效的,原因有二:
编码标准可能难以严格执行
要想出一个好的答案是很困难的。
I think that the second reason here is much more important than the first, because deciding on a coding standard can easily become a political matter and be subject to revision later on. Consider the following simplified case:
您可以使用 stl 容器,但不能在自己的代码中使用模板。
People start complaining that they'd be more productive if they just were allowed to code this or that template class.
Though I used to use C++ for just about everything a few years ago, I'm beginning to strongly feel that C is preferrable in low-level tasks that need to be handled by either C or C++ and everything else should be done in some other language entirely. (Only possible exceptions being some specific high-performance problem domains, wrt. 闪电战)
因此,它实际上是 C 借用了一些 c + + ,但尽可能多地使用 c + + 编译器。正如其他人在答案中所说,我发现现在我实际上用这种方法学到了更多的 C + + ,而在 C 语言太复杂的地方,我使用了 C + + 。使用 RAII 的 Monitor/Lock 是我最近在处理多线程程序和另一个类似的用于打开/关闭文件的结构时使用的方法之一。
这已经不再是有效的 C 了。(你可以使用 C 风格的强制转换,这种情况下它会在 C 中编译,但是被大多数 C + + 编码标准和许多 C 程序员所回避; 见证“不要强制转换 malloc”的注释遍布 Stack Overflow)。
它们不是同一种语言,如果你有一个 C 语言的现有项目,你不会仅仅为了使用一个库而用另一种语言重写它。您更愿意使用可以用所使用的语言进行接口的库。(在某些情况下,使用几个 extern "C"包装器函数就可以做到这一点,具体取决于 C + + 库的模板/内联程度。)
拿我正在做的一个项目中的第一个 C 文件来说,如果你把 gcc std=c99换成 g++,会发生这样的情况:
sandiego:$ g++ -g -O1 -pedantic -mfpmath=sse -DUSE_SSE2 -DUSE_XMM3 -I src/core -L /usr/lib -DARCH=elf64 -D_BSD_SOURCE -DPOSIX -D_ISOC99_SOURCE -D_POSIX_C_SOURCE=200112L -Wall -Wextra -Wwrite-strings -Wredundant-decls -Werror -Isrc src/core/kin_object.c -c -o obj/kin_object.o | wc -l
In file included from src/core/kin_object.c:22:
src/core/kin_object.h:791:28: error: anonymous variadic macros were introduced in C99
In file included from src/core/kin_object.c:26:
src/core/kin_log.h:42:42: error: anonymous variadic macros were introduced in C99
src/core/kin_log.h:94:29: error: anonymous variadic macros were introduced in C99
...
cc1plus: warnings being treated as errors
src/core/kin_object.c:101: error: ISO C++ does not support the ‘z’ printf length modifier
..
src/core/kin_object.c:160: error: invalid conversion from ‘void*’ to ‘kin_object_t*’
..
src/core/kin_object.c:227: error: unused parameter ‘restrict’
..
src/core/kin_object.c:271: error: ISO C++ does not support the ‘z’ printf length modifier
src/core/kin_object.c:271: error: ISO C++ does not support the ‘z’ printf length modifier
总共有69行错误,其中4行是无效的转换,但主要是针对存在于 C99中但不存在于 C + + 中的特性。
我用这些功能不是为了好玩。将它移植到另一种语言需要做大量的工作。
因此,这种说法显然是错误的
[a] C compiler is almost certainly really a C++ compiler, so there are no software cost implications
将现有的 C 代码移植到 C + + 的过程子集中通常会有显著的成本影响。
因此,建议使用 ’使用 C + + std: : queue 类’作为在 C 中查找队列的库实现的问题的答案比建议使用 使用目标 C和 ’使用 JNI 调用 Javajava.util. Queue 类’或 呼叫 CPython 库-Objective C 实际上是 C (包括 C99)的一个适当的超集,并且 Java 和 CPython 库都可以直接从 C 调用,而不必将不相关的代码移植到 C + + 语言。
当然,您可以为 C + + 库提供一个 C 外观,但是一旦您这样做了,C + + 就与 Java 或 Python 没有什么不同了。
我觉得 C 更便携。大约5年前,我做了一些工作,将代码移植到不同风格的 Unix (AIX、 Irix、 HPUX、 Linux)。C 代码很容易移植,但是我们在跨平台移植一些 C + + 代码时遇到了各种各样的问题。也许这只是一个不成熟的开发环境,但是出于这个原因,我更愿意使用 C 而不是 C + + ..。
There are three reasons I can think of. One is that C is more suited for embedded systems, due to the small size of its binaries and the wider availability of C compilers on any system. The second is portability: C is a smaller language, and and ANSI C code will compile anywhere. It's easier to break portability in C++. The last one is the language itself. C++ is harder, and is most definitely a very poorly designed language. Torvalds gripes are reported above. You may also want to look at the C++ Frequently Questioned Answers (http://yosefk.com/c++fqa/).
I know it's possible to bind C++ libraries, but AFAICT it's not the same. I've used Qt (v3 and v4) in other languages and it's not anywhere near as nice to use: they feel like writing C++ in some other language, not like native libraries. (You have to pass C++ method sigs as strings!)
如果您正在编写一个只能使用一次的函数,或者您认为整个世界都是 C + + ,那么 C + + 可能是一种更好的语言。如果您从一开始就为语言的可移植性进行设计,那么 C 语言似乎是一种更简单的语言。
C 语言的主要优点是,当您查看某段代码时,您可以看到实际发生了什么(是的,预处理程序: 使用 -E 编译,然后您就可以看到它)。当您查看一些 C + + 代码时,往往会发现有些东西是不正确的。在这里,构造函数和析构函数会根据作用域或赋值被隐式调用,而运算符重载可能会出现令人惊讶的行为,即使这种行为并没有被严重滥用。我承认我是一个控制狂,但我得出的结论是,对于一个想要编写可靠软件的软件开发人员来说,这并不是一个坏习惯。我只是想有一个公平的机会告诉大家,我的软件完全做到了它应该做的事情,同时也不会有不好的感觉,因为我知道它仍然有很多 bug,当我查看导致它们的代码时,我甚至不会注意到它们。
C++ also has templates. I hate and love them, but if anyone says he or she fully understands them I call him/her a liar! That includes the compiler writers as well as the folks involved in defining the standard (which becomes obvious when you try to read it). There are so many absurdly misleading corner cases involved that it's simply not possible to consider them all while you write actual code. I love C++ templates for their sheer power. It's really amazing what you can do with them, but they can likewise lead to the strangest and hardest to find errors one can (not) imagine. And these errors actually happen and not even rarely. Reading about the rules involved to resolve templates in the C++ ARM almost makes my head explode. And it gives me the bad feeling of wasted time having to read compiler error messages that are several 1000 characters long for which I need already 10 minutes or more to understand what the compiler actually wants from me. In typical C++ (library) code you also often find a lot of code in header files to make certain templates possible which in turn makes compile/execute cycles painfully slow even on fast machines and requires recompilation of large parts of the code when you change something there.
C + + 也有常量陷阱。除了最琐碎的用例之外,您要么避免使用常量,要么迟早要放弃它,或者在代码基础发展时重构大部分代码,特别是当您即将开发一个漂亮而灵活的 OO 设计时。
C + + 比 C 具有更强的类型,这很棒,但是有时候当我尝试编译 C + + 代码时,我感觉自己像在喂电子鸡。我通常从中得到的大部分警告和错误并不是我做了什么不起作用的事情,而只是编译器不喜欢我这样做或者不这样做而没有强制转换或者添加一些额外的关键字。
These are just some of the reasons why I don't like C++ for software that I write alone only using some allegedly robust external libraries. The real horror begins when you write code in teams with other people. It almost doesn't matter whether they are very clever C++ hackers or naive beginners. Everybody makes errors, but C++ makes it deliberately hard to find them and even harder to spot them before they happen.
使用 C + + 时,如果不一直使用调试器,你会感到迷失,但我希望能够在头脑中验证代码的正确性,而不必依赖调试器来发现我的代码运行在我从未预料到的路径上。实际上,我尝试在我的大脑中运行所有的代码,尝试获取它所有的分支,甚至在子例程中等等,并且只是偶尔使用一个调试器,只是为了看看它在我为它准备的所有舒适的地方运行得多么好。编写和执行如此多的测试用例,以至于所有的代码路径都被用于各种各样奇怪的输入数据的组合中,这简直是不可能的。所以你可能不知道 C + + 程序中的 bug,但这并不意味着它们不存在。C + + 项目的规模越大,我的信心就越低,因为即使它能够完美地运行我们手头的所有测试数据,它也不会有很多未被检测到的 bug。最后,我把它扔掉,用其他语言或其他语言的组合重新开始。
我可以继续说,但我想我已经说得很清楚了。所有这些都让我在用 C + + 编程时感到效率低下,让我对自己代码的正确性失去信心,这意味着我不会再使用它,而我仍然使用和依赖我20多年前编写的 C 代码。也许仅仅是因为我不是一个优秀的 C + + 程序员,或者也许是因为我在 C 语言和其他语言方面相当出色,这让我意识到当我涉及到 C + + 的时候,我实际上是一个多么差劲的人,而且我永远无法完全理解它。
On a scale from 0 - 10 I probably would rate C at 2 or 3 whereas C++ would be between 8-10. I'd argue C++ is one of the most complex languages but I do not know e.g Ada, PL1 or the like, so maybe it's not that complex in comparison to some other language.
C + + 继承了 C 语言的所有复杂性,因此它不能低于 C 语言的复杂性水平。
就我个人而言,使用一些脚本语言和 C 语言会更舒服一些。所以最后一个人必须回答下面的问题。“越多越好吗?”
大多数人似乎认为 C 和 C + + 之间有某种联系,但是他们错了。C + + 是一种与 C 完全不同的语言。
在 C + + 中,我们考虑对象以及它们之间的关系。在 C 语言中,使用 API 进行思考。这就像是第一天和第十七天的区别。
A poor analogy: if someone adds Chinese to English and calls it English++, you probably wouldn't feel comfortable to add a Chinese line to your latest love letter, because it's so much easier to express love in this part of English++.
The complexity, pitfalls of the language add too much distraction, and sometimes hurt productivity. Instead of focus on the job itself, I often found myself fighting with the language itself. Java/python are more productive alternatives.
调试损坏的 C 代码通常比调试损坏的 C + + 代码要简单得多。
与 Java/C # 不同,这个 C++标准程式库几乎没有超出 C 标准库的范围。
一些著名的程序员像 Linus Torvalds (Linux)和理查德·斯托曼(Emacs)不喜欢 C + + 。
将 C 增强为面向对象语言的尝试有很多种: C + + 、 C # 和 Objective-C。(Java 和朋友只是 C # 的一种风格,还有更多的问题)
C# implemented OO well and completely, but at the cost of the possibility of reverting to procedural design without introducing either hassle or code smell. Also, the introduction of a virtual machine made it difficult to write code that is anywhere near low level and it can never be self-hosted as the virtual machine itself have to be implemented in some language that can run natively. Java is even more problematic by making primitive types second-order citizen. (In C#, you have System.Int32 (a primitive type, int) : System.ValueType : System.Object, which makes primitive types still objects, but in Java primitive types are not objects at all). However, it is the most portable as compiled binaries that runs under virtual machines are inherently binary compatible under different platforms.
C + + 没有使用任何虚拟机,并保留了 C 指针,这使得它仍然适合于系统开发。(OS X 的内核 Darwin 主要是用 C + + 编写的,但是其中一个紧密的子集没有模板、多重继承或者 STL,本质上是 Objective-C 的一种看起来像 C + + 的方言。看看 OS X IOKit 文档,你就会发现)然而 C + + 根本没有解决那些经典的 C 问题,而是引入了更多的问题,包括最明显的可移植性问题。
Objective-C 在 C + + 和 C # 之间走到了一半,因为它是 C (任何版本)和修改后的 Smalltalk 方言的简单混合。与 C # 一样,Smalltalk 将所有东西都视为对象。它也不使用虚拟机,它仍然可以(需要!)使用指针,因此它仍然可以用作系统开发语言。(奇怪,为什么没有人这样做?我想分支 Minix,并尝试用最小的汇编程序和 C 实现一个内核,大部分是 Objective-C)与适当的库 Objective-C 是基本上代码兼容(也就是说,需要重新编译,但没有代码更改)之间的平台就像 C。