与C语言相比,C ++的局限性是什么?

时间:2009-03-16 09:54:13

标签: c++ c

以下是C ++的好处

  • C ++提供了他们所询问的具体功能
  • 他们的C编译器几乎肯定是一个C ++编译器,所以没有软件成本影响
  • C ++和C
  • 一样便携
  • C ++代码可以和C一样有效(或者更多,或者更少)

是否有任何具体原因和特定情况,其中必须使用C over C ++?

参考此问题:Library for generics in C

不重复,因为这个问题是关于语言限制而不是关于是否应该学习一种语言而不是另一种语言。

Peter Kirkham的帖子对我来说是最有用的,特别是关于我没有考虑的C99问题,所以我接受了它。感谢参与其他所有人。

32 个答案:

答案 0 :(得分:136)

  

这是由我给当前问题的一个答案提示的,该问题询问C的泛型库 - 提问者特别声明他们不想使用C ++。

C是一种完整的编程语言。 C不是C ++的任意子集。 C根本不是C ++的子集。

这是有效的C:

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

要使其编译为C ++,您必须编写:

foo_t* foo = static_cast<foo_t*>( malloc ( sizeof(foo_t) ) );

不再是有效的C. (你可以使用C风格的强制转换,它可以在C中编译,但是大多数C ++编码标准都会避开,许多C程序员也会避开;见证Stack overflow上的“不要抛出malloc”注释)


它们不是同一种语言,如果您在C中有现有项目,则不希望使用其他语言重写它只是为了使用库。您更愿意使用可以使用您正在使用的语言进行交互的库。(在某些情况下,这可以通过一些extern "C"包装函数实现,具体取决于C ++库的模板/内联方式。)< / p>

在我正在处理的项目中获取第一个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编译器几乎可以肯定是一个C ++编译器,因此没有软件成本影响

将现有C代码移植到C ++的过程子集中通常会产生很大的成本影响。

所以建议'使用C ++ std :: queue class'作为问题的答案,在C中查找队列的库实现比建议'使用目标C'< / em>和'使用JNI''调用Java java.util.Queue类调用CPython库' - Objective C实际上是C的正确超集(包括C99)和Java和CPython库都可以直接从C调用,而不必将不相关的代码移植到C ++语言。

当然,您可以为C ++库提供C外观,但是一旦您这样做,C ++与Java或Python没有什么不同。

答案 1 :(得分:114)

我意识到这既不是专业也不是特别好的答案,但对我而言,这只是因为我真的很喜欢C. C小而简单,我可以将整个语言融入我的大脑,C ++对我来说似乎总是如此各种各样的巨大庞大的混乱,我很难在grokking。由于这个原因,我发现每当我编写C ++时,我最终会花费更多的时间来调试和敲击硬表面,而不是在编写C时。我再次意识到很多这很大程度上是由于我自己的“无知”。

如果我选择,我将编写所有高级内容,例如python中的接口和数据库交互(或可能是C#)以及所有必须在C中快速的东西。对我来说,这给了我最好的所有的世界。用C ++编写所有东西感觉就像是最糟糕的世界。

修改 我想补充一点,如果你要成为一个项目的几个人或者可维护性是优先考虑的话,我认为具有一些C ++特性的C在很大程度上是一个坏主意。关于什么构成'少数'以及哪些比特应该在C中完成以及哪些比特在C ++中最终导致一个非常精神分裂的代码库,将会有分歧。

答案 2 :(得分:58)

在某些现实环境中,例如低级嵌入式系统,不支持C ++。并且有一个很好的理由:C对于这样的东西很容易就够了,所以为什么要用更大的东西?

答案 3 :(得分:49)

我讨厌用C ++编程。

答案 4 :(得分:38)

可能有以下几个原因:

  • 缺乏支持 - 并非每个C编译器都是C ++编译器。并非所有编译器都特别符合标准,即使他们声称支持C ++。而一些C ++编译器会产生无望的膨胀和低效的代码。一些编译器具有标准库的可怕实现。内核模式开发通常不可能使用C ++标准库,以及一些语言功能。如果你坚持使用该语言的核心,你仍然可以编写C ++代码,但是切换到C可能更简单。
  • 熟悉。 C ++是一门复杂的语言。教C之人比C ++更容易,而且找一个优秀的C程序员比一个优秀的C ++程序员更容易。 (这里的关键字是“好的”。有很多C ++程序员,但大多数都没有正确学习语言)
  • 学习曲线 - 如上所述,教某人C ++是一项艰巨的任务。如果您正在编写一个将来必须由其他人维护的应用程序,而这些应用程序可能不是C ++程序员,那么用C语言编写它会使得它更容易掌握。

我仍然更喜欢用C ++编写,当我可以逃脱它时,总的来说,我认为好处大于缺点。但我也可以看到在某些情况下使用C的论点。

答案 5 :(得分:30)

有很多关于嵌入式编程,性能和内容的争论,我不买。在这些领域,C ++很容易与C进行比较。的然而

就在最近用C ++编程超过15年之后,我一直在重新发现我的C根。我必须说,虽然C ++中有很好的功能可以让生活更轻松,但也有很多陷阱和一种“总是更好的方式”。你从未真正对你所做的解决方案感到高兴。 (不要误解我的意思,这可能是一件好事,但主要不是。)

C ++给你无限的枪声。这可能是好的,但不知怎的,你总是最终使用太多。这意味着您通过“漂亮”和“漂亮”的抽象层次,一般性等来伪装您的解决方案。

我发现回到C的原因是它实际上又是有趣的编程。花了这么多时间建模并思考如何最好地使用继承,我发现用C编程实际上使我的源代码更小,更易读。这当然取决于你的自律水平。但是在直接代码上放置过多的抽象是非常容易的,这实际上并不需要。

答案 6 :(得分:27)

C的主要优点是,当你查看一些代码时,你可以看到真正发生的事情(是的预处理器:用-E编译,然后你看到它)。当你看一些C ++代码时,往往不常见的事情。在那里你有构造函数和析构函数,它们基于作用域或由于赋值而被隐式调用,你有操作符重载,即使它没有被严重误用,也会产生令人惊讶的行为。我承认我是一个控制狂,但我得出的结论是,对于想要编写可靠软件的软件开发人员来说,这不是一个坏习惯。我只是想有一个公平的机会说我的软件完全按照它应该做的那样,同时我的胃里没有一种不好的感觉,因为我知道它仍然会有很多错误,我不会我甚至注意到我看到导致它们的代码。

C ++也有模板。我讨厌并爱他们,但如果有人说他或她完全理解他们,我称他/她为骗子!这包括编译器编写者以及参与定义标准的人(当你尝试阅读它时会变得很明显)。有很多荒谬的误导性案例涉及到在编写实际代码时根本无法全部考虑它们。我喜欢C ++模板,因为它们具有强大的功能。你可以用它们做什么真的很神奇,但它们同样可以导致最奇怪和最难找到错误的人可以(不)想象。而这些错误实际上发生了,甚至很少发生。阅读有关解决C ++ ARM模板所涉及的规则几乎让我头疼。并且它让我感觉浪费时间不得不阅读几千个字符长的编译器错误消息,我需要10分钟或更长时间来理解编译器实际上想要的内容。在典型的C ++(库)代码中,您还经常在头文件中找到大量代码以使某些模板成为可能,这反过来使得即使在快速机器上编译/执行周期也很慢,并且当您更改某些内容时需要重新编译大部分代码那里。

C ++也有const陷阱。除了最琐碎的用例之外,您可以避免使用const,或者您迟早要将其丢弃或者在它发展时重构代码库的大部分内容,尤其是当您即将开发一个漂亮而灵活的OO设计时。

C ++具有比C更强的类型,这很好,但有时我觉得在尝试编译C ++代码时我正在喂一个Tamagotchi。我通常从中得到的警告和错误的很大一部分并不是我做了一些不起作用的事情,而是编译器不喜欢我这样做的事情,如果没有在这里投出或添加一些额外的关键字,那里。

这些只是我不喜欢C ++软件的一些原因,我只使用一些据称强大的外部库来单独编写软件。当你与其他人一起编写代码时,真正的恐怖就开始了。它们是非常聪明的C ++黑客还是天真的初学者并不重要。每个人都会犯错误,但是C ++会故意找到它们,甚至更难以发现它们。

使用C ++,你总是在不使用调试器的情况下丢失,但我希望能够在头脑中验证代码的正确性,而不必依赖调试器来查找我在路径上运行的代码有所期待。我实际上尝试在我的头脑中运行我的所有代码并尝试获取它拥有的所有分支,甚至在子程序等中。并且偶尔使用调试器只是为了看看它在我为它准备的所有舒适的地方运行得如何。编写和执行如此多的测试用例,使得所有代码路径都被用于所有类型的奇怪输入数据的组合是根本不可能的。所以你可能不知道C ++程序中的错误,但这并不意味着它们不存在。 C ++项目越大越低,我相信它不会有很多未被发现的错误,即使它与我们手边的所有测试数据完美匹配。最终我把它丢弃并重新开始使用其他语言或其他语言的组合。

我可以继续,但我想我现在已经说清楚了。当我使用C ++进行编程并且让我对自己的代码的正确性失去信心,这意味着我将不再使用它,而我仍然使用并依赖于我编写的超过20个C代码时,所有这一切都让我感到无益几年前。也许这仅仅是因为我不是一个优秀的C ++程序员,或者在C语言方面表现相当优秀,其他语言让我能够认识到在C ++方面我实际上是一个什么样的人,而且我永远无法完全理解它

生命短暂......

答案 7 :(得分:20)

在低级嵌入式环境中,一些“软件工程师”将具有EE背景并且几乎没有掌握C. C ++更复杂,其中一些人只是害怕学习一门新语言。因此,C被用作最小公分母。 (在你建议摆脱这些家伙之前,他们至少和那些不了解核心模拟东西的CS专业人士一样重要。)

从继承和维护两者的经验谈起:C语言中的可怕设计难以理解,放松并重构为可用的东西。

C ++中的一个可怕的设计无限糟糕,因为随机的抽象层会让你的大脑在代码库周围发挥作用,试图找出哪些代码将在哪种情况下执行。

如果我必须与我知道不会产生出色设计的工程师合作,我宁愿拥有前者而不是后者。

答案 8 :(得分:19)

即使对嵌入式系统和类似的东西进行编程,我也没有看到任何个人不喜欢的理由。在C ++中,您仅为您使用的功能支付开销。在C ++开销过高的某些特定情况下,您可以使用C ++的C子集。这就是说,我认为一些C程序员高估了一些C ++结构的开销。让我列举一些例子:

  • 与普通函数相比,类和成员函数的开销为零(除非使用虚函数,在这种情况下与使用函数指针相比​​没有开销)
  • 模板的开销很小(通常根本没有开销)

一个合理的原因是当你为没有合适的C ++编译器的平台编程时(根本没有C ++编译器,或者编译器存在,但是实现很差,并且对某些C ++特性施加了不必要的高开销)

答案 9 :(得分:12)

为什么限制英语口语?也许你会成为塞尔维亚人更有创意的作家。

这是相同的论点,有明显的谬误。如果您有任务,并且您的舒适工具可以有效地解决任务,那么您可能会使用舒适的工具。

答案 10 :(得分:10)

C ++有更长的学习曲线。 C只有很少的构造需要注意,然后你就可以开始编写功能强大的软件了。在C ++中,你需要学习C基础,然后是OO和泛型编程,异常等。经过一段时间你可能知道大多数功能,你可能会使用它们,但你仍然不知道编译器将如何翻译他们,他们有或没有隐含的开销。这需要很多时间和精力。

对于一个专业项目,这个论点可能不算数,因为你可以雇用已经熟悉C ++的人。但是在开源项目中,C仍然使用了widley,人们会选择他们喜欢的语言并且能够使用。考虑到并非每个OS程序员都是专业程序员。

答案 11 :(得分:10)

我使用C,或者在编写库代码时至少导出一个C接口。

我不想要不明确的ABI麻烦。

答案 12 :(得分:10)

我想跟进Dan Olson的回答。我相信人们担心C ++的潜在危险和适得其反的特性,并且理所当然。但与丹所说的不同,我不认为简单地决定编码标准是有效的,原因有两个:

  1. 编码标准可能难以严格执行
  2. 想出一个好的可能很难。
  3. 我认为这里的第二个原因比第一个原因重要得多,因为决定编码标准很容易成为一个政治问题,并在以后进行修订。请考虑以下简化案例:

    1. 您可以使用stl容器,但不能在任何自己的代码中使用模板。
    2. 人们开始抱怨说,只要他们允许对这个或那个模板类进行编码,他们就会更有效率。
    3. 修改了编码标准以允许这样做。
    4. 将斜坡滑动到一个过于复杂的编码标准,没有人遵循,并使用标准本应防止的那种危险代码,并结合标准周围的过多官僚作风。
    5. (标准在步骤3中没有修改的替代方案在经验上太不可能考虑,反正也不会那么好。)

      虽然几年前我曾经使用过几乎所有的C ++,但我开始强烈地认为C在需要由C或C ++处理的低级任务中是首选的,其他一切都应该完成用其他语言完全。 (只有可能的例外是某些特定的高性能问题域,wrt。Blitz++

答案 13 :(得分:9)

我还没有看到过一点,我认为这是最重要的一点:

我每天使用的大多数库都是带有Python,Ruby,Perl,Java等绑定的C库。从我所看到的,用19种不同的语言绑定来包装C库要容易得多。它是包装C ++库。

例如,我曾经学过Cairo次,之后又用3种或4种不同的语言。大赢!我宁愿编写一个可以在将来再次使用的程序,编写一个可以很容易被其他编程语言采用的程序是一个极端的例子。

我知道绑定C ++库是可能的,但AFAICT并不相同。我已经在其他语言中使用过Qt(v3和v4)并且使用起来并不是很好:他们感觉就像用其他语言编写C ++,而不是像本机库一样。 (你必须将C ++方法sigs作为字符串传递!)

如果您正在编写一次使用的函数,或者如果您认为全世界都是C ++,那么C ++可能是一种更好的语言。如果你从一开始就设计语言可移植性,C似乎是一种更容易的语言。

答案 14 :(得分:9)

我从未见过使用C over C ++的任何论据,我认为这些论点令人信服。我认为大多数人都害怕C ++提供的某些功能,通常是合理的。然而,这并不能说服我,因为人们可以通过编码标准来强制执行是否使用某些功能。即使在C中,也有很多你想要避免的东西。完全抛弃C ++本质上是说它没有提供超过C的实际好处,这有助于编写更好的代码,这是一种我认为非常无知的观点。

此外,人们似乎总是提出没有C ++编译器的平台的情况。当然C在这里是合适的,但我认为现在很难找到像这样的平台。

答案 15 :(得分:7)

Windows内核开发不支持c ++(遗憾的是)。

答案 16 :(得分:6)

你可以阅读一个有趣的咆哮,说明为什么Linus Torvalds喜欢C here

答案 17 :(得分:5)

mac上的本机代码是objective-c。 PC上的本机代码是c(window.h)或c ++(mfc)。这两种环境都允许您在很少或没有更改的情况下使用c。当我想要一个代码库来跨平台时,似乎是个不错的选择。

答案 18 :(得分:4)

我可以想到几个原因。

可能没有令人满意的C ++编译器。 C ++是一个更大的语言,我在无法处理现代C ++的系统上运行C编译器。

提问者或与其合作的人可能熟悉C而不是C ++。

该项目可能在C中。虽然可以向C添加一些C ++功能,但这很容易导致无法维护的混乱。我建议选择一种语言或其他语言(通常是C ++,实际上)。

提问者可能对C ++的学习曲线有过时的看法。 (当正确接近时,它比C更容易。我见过的大多数介绍性书籍都没有正确接近它。)

请记住,C和C ++是两种不同的语言,随着时间的推移越来越不同。同时编码是一个坏主意,使用类似C语言的C ++子集忽略了C ++的大部分优点。

答案 19 :(得分:3)

我将C ++与C编程一起使用有两个原因:

  • vectorstring让数组内存管理远离我
  • 严格的类型检查和演员以警告和/或捕捉我将错过的所有滋扰。

所以C真的借用了一些c ++,但尽可能多地使用c ++编译器。正如其他人在答案中所说的那样,我现在发现我实际上正在以这种方式获取更多C ++,而C将过于涉及,我使用的是C ++。使用RAII进行监视/锁定是我最近在处理多线程程序和打开/关闭文件时使用的其他类似结构之一。

答案 20 :(得分:3)

我认为C更便携。大约5年前,我做了一些工作,将代码移植到许多版本的unix(AIX,Irix,HPUX,Linux)。 C代码很容易移植,但我们在移植一些C ++代码时遇到了各种问题。也许这只是不成熟的开发环境,但我更倾向于使用C而不是C ++ ......

答案 21 :(得分:3)

如果您在具有两种语言的环境中工作,则可以将C用于一些性能关键的低级函数,并将更多功能/高级语言(如C#/ Java)用于业务逻辑。 如果C ++代码用于这些函数,则JNI /非托管代码需要C-Wrappers,这使得事情比仅使用C更复杂。

答案 22 :(得分:3)

  1. C是一种简单的语言,C ++不是。对于许多人来说,C ++太复杂而无法完全掌握,请参阅http://en.wikipedia.org/wiki/C%2B%2B#Criticism

  2. 由于复杂性,不同的程序员通常只掌握语言的不同子集。它使阅读其他人的代码变得痛苦。

  3. 语言的复杂性,陷阱会增加太多的注意力,有时会影响生产力。我没有专注于工作本身,而是经常发现自己正在与语言本身作斗争。 Java / python是更有效的替代方案。

  4. 调试损坏的C代码通常比调试损坏的C ++代码简单得多。

  5. 与Java / C#不同,C ++标准库几乎没有超出C标准库的范围。

  6. Linus Torvalds(Linux)和Richard Stallman(Emacs)等一些着名程序员不喜欢C ++。

答案 23 :(得分:1)

大多数程序员认为每个人都认为质量是高优先级,这是理所当然的。情况并非总是如此。如果你习惯使用C语言,那么C ++可能会在幕后为你做太多事情。 C ++中类型检查的严格性似乎也受到限制。许多人愿意冒险介绍C ++可以帮助防止这些“滋扰”的各种错误。

答案 24 :(得分:1)

我能想到三个原因。一个是C更适合嵌入式系统,因为它的二进制文件很小,并且C编译器在任何系统上都有更广泛的可用性。第二个是可移植性:C是一种较小的语言,ANSI C代码将在任何地方编译。在C ++中破解可移植性更容易。最后一个是语言本身。 C ++更难,而且绝对是一种设计很差的语言。上面报道了Torvalds抱怨。您可能还想查看C ++常见问题解答(http://yosefk.com/c++fqa/)。

答案 25 :(得分:1)

便携性可能是一个问题。与Gordon Carpenter-Thomp的答案不同,我建议在不同的linux / unix版本上使用不同版本的libstdc ++。有关此问题的详细讨论,请参阅this link。一点摘录:

  

C ++应用程序的不同部分使用的运行时支持代码需要兼容。如果程序的一部分需要dynamic_cast或捕获另一部分提供的对象,则两个部分必须就某些实现细节达成一致:如何查找vtable,如何展开堆栈等等。

     

对于C ++和其他一些具有类似功能的GCC支持的语言,这些细节由C ++ ABI指定。每当GCC使用的ABI发生变化时,您最终会得到不同GCC版本生成的不兼容库。对于普通C来说也是如此,但是C ABI更加简单并且已经存在了很长时间,所以它相当稳定。

答案 26 :(得分:1)

我可以在这两方面遵循许多建议。但最终归结为 a)比较简单 b)可比较的复杂。

我不知道某人是否“发明了”某种东西 语言复杂度测量。

在0到10的范围内,我可能会将C评为2或3,而C ++则介于8-10之间。我认为C ++是最复杂的语言之一,但我不知道例如Ada,PL1等,所以也许它与其他语言相比并不复杂。

C ++继承了C的所有复杂性,因此它不能低于C的复杂程度。

对于我来说,使用某些脚本语言和C会更加舒服。所以最后我必须回答以下问题。 “总是更好吗?”

答案 27 :(得分:1)

我在C中发现的最有用的东西是缺少名称空间和重载:函数和符号名称是唯一标识符。要查找使用这些符号的位置,您只需grep通过源代码文件,搜索结果就会显示位置。

将新功能或组件连接到旧的和纠结的系统时,这一点非常重要。

如果没有复杂的调用图构建工具,您无法在C ++中轻松完成此任务。

答案 28 :(得分:0)

大多数人似乎认为C和C ++在某种程度上相关,但他们遗憾地错了。 C ++是一种完全不同于C语言的语言。

在C ++中,您可以根据对象以及它们彼此之间的关系来思考。在C中,您考虑的是API。这就像天和17之间的区别。

一个不好的比喻:如果有人将中文添加到英文并称之为英文++,你可能会觉得在你的最新情书中添加中文系列会感觉不舒服,因为在这部分英文++中表达爱情要容易得多。

答案 29 :(得分:0)

以下是将项目限制为C可能有益的所有原因:

  • 编译速度更快,因为语言更简单
  • 需要更少的运行时支持,使其更适合低级别环境
  • 更容易与其他语言交互
  • 支持堆栈上可变大小的数组
  • 更容易阅读汇编代码,因为没有名称错误
  • 允许不同编译器生成的代码轻松组合,因为它是事实上的标准应用程序二进制接口

答案 30 :(得分:0)

尝试将C语言增强为面向对象语言有各种各样的尝试:C ++,C#和Objective-C。 (Java和朋友只是C#的一种风格,有更多的问题)

C#完全实现了OO,但代价是在不引入麻烦或代码气味的情况下恢复程序设计的可能性。此外,虚拟机的引入使得编写任何接近低级别的代码变得困难,并且它永远不能自托管,因为虚拟机本身必须以某种可以本地运行的语言实现。通过使原始类型为二阶公民,Java更成问题。 (在C#中,您有System.Int32(基本类型,int):System.ValueTypeSystem.Object,它使原始类型仍为对象,但在Java原始类型中不是对象在所有)。但是,它是最便携的,因为在虚拟机下运行的已编译二进制文件在不同平台下具有固有的二进制兼容性。

C ++没有使用任何虚拟机,并保留了C指针,这使得它仍然适合于系统开发。 (OS X的内核,Darwin,主要是用C ++编写的,但是其中一个紧密的子集没有模板,多重继承或STL,本质上是一种看起来像C ++的Objective-C方言。查看OS X IOKit文档和你会发现)然而,C ++并没有解决那些经典的C问题,同时引入了更多的问题,包括可移植性问题,这显然是最明显的。

Objective-C在C ++和C#中间走了一半,因为它是C(任何版本)和修改后的Smalltalk方言的简单混合。 Smalltalk,就像C#一样,将所有东西视为对象。它也不使用虚拟机,它仍然可以(需要!)使用指针,因此它仍然可以用作系统开发语言。 (奇怪为什么没有人这样做?我想分叉Minix并尝试用最少的汇编程序和C实现内核,主要是Objective-C)使用适当的库Objective-C主要是代码兼容的(也就是说,需要重新编译但是平台之间没有代码更改,就像C一样。

答案 31 :(得分:0)