在C ++代码中使用纯C库会导致性能下降/损失吗?

时间:2017-12-30 02:26:28

标签: c++ c performance c-libraries

我看到了这个链接,但我不是要求使用“extern”的代码性能下降。我的意思是没有“extern”,在C ++中使用C库时是否存在“上下文切换”? Are there any problems when using pure C (not class-wrapped) functions in C++ application?

3 个答案:

答案 0 :(得分:36)

C和C ++都是编程语言规范(用英文编写,参见例如n1570的C11规范)并且不谈性能(但是关于程序的行为,即约semantics)。

但是,您可能会使用GCCClang之类的编译器,这些编译器不会带来任何性能损失,因为它构建了相同类型的中间内部表示(例如,GCC的GIMPLE, C语言和C ++语言,以及C和C ++代码使用兼容的ABIcalling conventions

实际上extern "C"不会更改任何调用约定但会禁用name mangling。但是,它对编译器的确切影响是特定于该编译器的。它可能(或不)禁用inlining(但在GCC中考虑-flto进行链接时优化。)

某些C编译器(例如tinycc)会生成性能较差的代码。甚至GCCClang,与-O0一起使用或明确启用optimization时(例如passing -O1-O2等...)可能会生成慢速代码(默认情况下禁用优化)。

BTW,C ++旨在与C互操作(强大的约束解释了C ++的大部分缺陷)。

在某些情况下,正版C ++代码可能比相应的正版C代码略快。例如,要对数字数组进行排序,您将在正版C ++中使用std::arraystd::sort,并且排序中的比较操作可能会被内联。使用C代码,您只需使用qsort,每次比较都会通过间接函数调用(因为编译器不会内联qsort,即使理论上它可以......)。

在其他一些情况下,真正的C ++代码可能略微更慢;例如,::operator new的几个(但不是全部)实现只是调用malloc(然后检查失败),但没有内联。

实际上,从C ++代码调用C代码或从C代码调用C ++代码没有任何代价,因为调用约定是兼容的。

C longjmp工具可能比抛出C ++异常更快,但它们没有相同的语义(参见stack unwinding),longjmp与C ++代码混合不好

如果你非常关心性能,那么在你的代码和基准测试中写两次(在真正的C和真正的C ++中)。您可能会观察到C和C ++之间的微小变化(最多几个百分点),所以我根本不会打扰(并且您的性能问题实际上是不合理的)。

Context switch是与operating systemmultitasking相关的概念,在processes期间运行machine code可执行文件的preemption上发生。如何获得executable(来自C编译器,来自C ++编译器,来自Go编译器,来自SBCL编译器,或者是其他语言(如Perl或字节码Python)的解释器)是完全无关紧要的(因为上下文切换可以在interrupts期间的任何机器指令处发生。阅读一些像Operating Systems: Three Eeasy Pieces这样的书。

答案 1 :(得分:13)

在基本级别,从C ++代码调用C库时,您将看不到任何类型的“切换”性能损失。例如,从C ++调用另一个转换单元中定义的C方法应该具有与在另一个转换单元中调用C ++中实现的相同方法(以相同的C类方式)大致相同的性能。

这是因为C和C ++编译器的常见实现最终将源代码编译为本机代码,并且使用C ++可能出现的相同类型的extern "C"有效地支持调用call函数。呼叫。调用约定通常基于平台ABI,在任何一种情况下都是相似的。

除了基本事实之外,在调用C函数时可能仍存在一些性能缺点,而不是在C ++中实现相同的函数:

  • 在C中声明并声明extern "C"并且从C ++代码调用的函数通常不会被内联(因为根据定义它们没有在头文件中实现),这会抑制整个主机可能非常强大的优化< SUP> 0
  • C代码 1 中使用的大多数数据类型都不能由C代码直接使用,例如,如果您的C ++代码中有std::string,则需要选择一种不同的类型将其传递给C代码 - char *很常见,但会丢失有关显式长度的信息,这可能比C ++解决方案慢。许多类型没有直接的C等价物,因此您可能会遇到代价高昂的转换。
  • C代码使用mallocfree进行动态内存管理,而C ++代码通常使用newdelete(并且通常更喜欢隐藏其他类后面的调用尽可能)。如果你需要用一种语言分配内存,而这种语言将在其他语言中被释放,这可能会导致你不需要回拨“其他”语言来做免费,或者可能不必要的副本等。
  • C代码经常大量使用C标准库例程,而C ++代码通常使用C ++标准库中的方法。由于存在大量功能重叠,因此C和C ++的混合可能比纯C ++代码具有更大的代码占用空间,因为使用了更多的C库方法 2

上述问题仅适用于纯C ++实现与C语言的对比,并不意味着在调用C时性能会下降:它实际上是回答“为什么可以在混合中编写应用程序” C和C ++比纯C ++慢?“此外,上述问题主要是对非常短的呼叫的关注,其中上述开销可能很大。如果你在C中调用一个冗长的函数,那就不是问题了。 “数据类型不匹配”可能仍然会让你感到厌烦,但这可以在C ++方面进行设计。

0 有趣的是,链接时优化实际上允许C方法为inlined in C++ code,这是LTO的一个鲜明的好处。当然,这通常取决于使用适当的LTO选项从源代码构建C库。

1 例如,除了标准布局类型之外的其他任何东西。

2 至少部分地通过许多C ++标准库调用最终委托C库例程进行“重”提升这一事实,例如std::copy如何调用{{memcpy来解决这个问题。 1}}或memset在可能的情况下以及大多数new实施最终如何调用malloc

答案 2 :(得分:4)

C ++从一开始就发展和变化很多,但是在设计上它与C语言向后兼容.C ++编译器通常是用C编译器构建的,但更加现代化link-time optimizations。我认为很多软件可以在用户空间和使用的库中可靠地混合使用C和C ++代码。 I answered a question recently涉及将C ++类成员函数指针传递给C实现的库函数。海报说这对他有用。因此,可能的C ++与C的兼容性比任何程序员或用户都认为的要好。

然而,C ++在许多不同的范例中工作,因为它是面向对象的,并且实现了整个范围的抽象,新数据类型和运算符。某些数据类型很容易翻译( bike_id date n 1: 1 2017-11-22 3 2: 1 2017-11-22 2 3: 1 2017-11-21 1 C字符串到char *),而其他数据类型则不然。 This section on GNU.org about C++ compiler options可能会引起一些兴趣。

混合两种语言时,我不会太担心或担心性能下降。最终用户,甚至程序员,几乎都不会注意到性能上有任何可测量的变化,除非他们处理大量的数据抽象。