【问题标题】:Is C notably faster than C++ [closed]C 明显比 C++ 快吗[关闭]
【发布时间】:2011-10-20 18:31:29
【问题描述】:

据我所知,所有脚本语言和核心科学程序通常都是用 C 编写的;这使得实现变得混乱,但在某种程度上直截了当。

我知道这些人希望最大限度地发挥他们的性能,但是使用 C 字符串和 C 结构与使用 C++ 类之间是否存在真正的区别? C++ 似乎以同样的方式工作,除了虚函数之外,它存储一个类函数一次,该类的每个实例都调用该函数。

是什么让 C 变得更快?在诸如 python 或 sqlite 之类的项目中,谁必须是最快的?

【问题讨论】:

  • “用任何语言写得好的代码总是比用任何其他语言写得不好的代码好。”
  • 这些项目中有许多是在 C++ 被广泛接受并处于合适状态之前开始的。惯性让人们继续使用 C。
  • @Will - 不。“一种语言是否比另一种语言快”是无法回答的。语言并不快,只有它们的实现。 “一种语言的 X 实现是否比另一种语言的 Y 实现更快?”可以通过分析来回答,但是你分析了什么?语言实现在各个领域都可以快也可以慢,毫无疑问,要测试所有这些是不可能的。一个更好的问题是“为什么语言设计者选择 X 语言而不是 Y 语言?”这有一个明确的答案(不同语言设计者给出的基本原理)并且更有可能有所帮助。
  • C 和 C++ 中相同的代码应该通常以完全相同的速度运行,例外是由于别名规则不同等而具有不同语义的代码。区别在于在 C 习语和 C++ 习语之间。如果您使用 C 或 C++ 中的最佳实践 C 习惯用法编写代码,它通常会比使用最佳实践 C++ 习惯用法编写的类似功能更轻、更快(并且处理的失败案例更少)(无论您是否编写它)在 C 或 C++ 中),但它可能会花费你更多的工作来编写。
  • C 的整体学习速度明显快于 C++ ;)

标签: c++ c performance


【解决方案1】:

语言本身并不是更快或更慢,解释器和编译器的效率可能更高或更低。

除此之外,高级语言提供的抽象层通常具有运行时成本。如果您不使用它们,编译器可能足够聪明,可以将它们删除,但如果语言的语义不允许安全地执行它,这可能是不可能的......如果您需要它们,请自己实现它们使用较低级别的语言可能会比使用“慢”语言慢。

【讨论】:

  • 脚本语言在遗传上比编译语言要慢,除非你编写了真正糟糕的编译代码
  • @Will03uk - 是什么阻止你为通常的脚本语言编写编译器?
  • @Chris 那么它就不是脚本语言了;脚本语言的含义是它被解释或编译字节码。一旦你编译它,它是不是一种编译语言
  • 这不是全部事实:语言语义确实很重要,因为它们决定了优化器可用的信息以及可以安全地做出哪些假设而无需执行整个程序分析;恰当的例子:C 或 luajit 中的 restrict 关键字 - 后者不会仅仅因为 Mike 是一个聪明人,而是因为 Lua 的语义非常干净(与例如 JavaScript)
  • @Christoph 我想说的是没有灵丹妙药。如果您需要动态调度、虚拟调用、代码热加载或鸭式输入等内容,那么开箱即用可能看起来“慢”的语言可能比 C 中的幼稚实现更快。
【解决方案2】:

正如 Bjarne 在 [D&E] 中提到的,有效性是 C++ 的主要目标之一。 因此,只有当程序员使用它的“额外”功能(如您提到的虚函数、rtt 信息等)时,C++ 才会更慢

所以我认为这更多是心理原因 - 使用 C 是因为它不允许“慢”C++ 特性。

【讨论】:

    【解决方案3】:

    我认为原因与其说是与性能有关,不如说是与互操作性有关。 C++ 语言比 C 语言更复杂,但从性能的角度来看,这两种语言都不应该有显着差异。一些 C++ 结构比 C 等效结构更快(std::sortqsort 快),并且可能有其他很好的例子。

    编辑:在互操作性方面...

    基本上,C++ 标准没有定义一些可能需要的东西,以便在使用不同编译器/版本创建的二进制文件之间轻松实现互操作性。这里最值得注意的问题是二进制中符号的命名约定。在 C 中,该语言定义了从代码中的每个符号到二进制符号名称的单个映射。一个名为my_function 的函数将在二进制文件中创建一个名为my_function 的符号。另一方面,由于函数重载等特性,C++ 函数的名称必须是mangled(翻译成二进制中不同的函数符号,编码参数的类型和返回类型),并且该标准没有定义如何执行修改。这反过来意味着 C++ 中的相同函数可以根据编译器编译为不同的符号(除非 extern "C" 用于强制 C++ 中的这些函数具有 C 互操作性)。

    最终,脚本语言和本机代码之间的接口无论如何都必须是 C 接口,即使其内部实现的细节可能是 C/C++/任何其他本机语言。

    (我故意不想卷入语言偏好的火焰战,C++ 确实很强大,但它也有点可怕,因为它是一种比 C 复杂得多的语言,而且有些东西看起来 简单可能会对性能产生影响)

    【讨论】:

    • 我想人们可以自信地说,现代的、惯用的 C++ 需要一个智能编译器才能充分利用内联、RVO、常量折叠等。这样一来,重量级 C++ 构造完全有可能在机器级别根本不明显,但是一个好的编译器对于 C++ 比对于 C 更重要。
    • @Kerrek SB:大多数现代 C++ 编译器(现代意味着最近几年)非常擅长识别惯用的C++ 结构和优化。 std::sort 就是一个这样的例子:默认使用的 std::less 仿函数并不比等效的 C 函数效率低,但我知道的所有编译器都会内联它(作为可用于内联的模板)并删除所有对 compare 函子的函数调用。
    • 有趣的是,Electronic Arts 的 EASTL 库的部分理由是他们发现 GCC 内联不好(而 MSVC 更好),因此标准库会导致太多未优化函数调用。在 EASTL 中,他们使用较少的间接来解决这个问题。谁知道这种推理在今天能站得住脚。
    【解决方案4】:

    C++ 通常用于科学程序。 C 语言在该领域的受欢迎程度可能正在减弱。 Fortran 作为一种“低级”语言仍然很受欢迎。

    在 C++ 中,“您只需为使用的内容付费。”所以没有什么比 C 更慢的了。特别是对于科学程序,表达式模板可以使用模板引擎执行一些自定义优化来处理程序语义。

    C 语言更适合 Python 等项目的原因是它易于阅读,因此更容易让更多的贡献者访问大型代码库。

    SQLite 需要较小的可执行代码大小,而 C 确实有一点优势。明智地使用 C++ 仍然允许在嵌入式应用程序中使用,但由于担心不需要的语言特性会蔓延,它不太受欢迎。

    【讨论】:

    • 请注意,C++ 确实名称修饰,而 C 没有,这使得其他语言更容易直接与 C 交互。 (在为 C++ 库创建 python 包装器之前,swig 实际上为您构建了 C++ 代码的 C 接口。)
    • @SamP C++ 具有禁用名称修改的功能,extern "C"。 Swig 碰巧使用 C 作为通用语言,但您可以在与 C 兼容的 C++ 子集中实现该包装器,而永远不要调用 C 编译器。
    • "SQLite 需要小的可执行代码大小,而 C 确实有一点优势。"我认为用惯用的 C++ 编写的 SQLite 不会比 C 实现更大或更慢。它肯定会少很多 C++ 代码,并且它可以提供可选的 LINQ 和编译时查询预优化和编译。 C 需要一个代码生成器,因此使用 SQLITE 你不能预编译查询。 C++ SQLITE 可以让您在没有任何干预 VM 代码的情况下使用 range-for 迭代记录,相比之下,它会使 C SQLITE 看起来像蜗牛一样。太糟糕了...
    • 实际上,一个典型的注重大小的嵌入式 SQLITE 应用程序有一个固定的查询集,并且数据库是从 flash 内存映射的,具有固定的模式,而 SQL 解释器和 VM 是自重的,如是很多其他的代码。我已经做了一些实验,使用“原始”C 编写查询,使用 SQLITE 中的低级页面访问,对于我的特定应用程序,我可以或多或少地丢弃 85% 的 SQLITE 代码。因此,如果有的话,SQLITE 由于不利用 C++ 而浪费了大量时间,但它针对的是没有 C++ 可用的平台,并且他们没有为查询实现 C 代码生成器。
    • @UnslanderMonica 1. C++ 二进制文件有异常处理表,即使它们是空的,也会增加一个边距。 2. SQLite 是基于字节码的。 C++ 中的编译时查询优化意味着在不能使用指针的 constexpr 函数中进行解析和分析。这表明架构发生了变化,使得产品不再是 SQLite。 3. 有没有办法保存字节码并从应用程序和库二进制文件中去除文本和解析器? 4. 无解析器或“无头”SQLite 可以与 C++ 仅头字节码生成器/优化器接口。
    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 2015-06-22
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 2010-10-11
    相关资源
    最近更新 更多