在C++代码中使用纯C库是否会降低性能?

Joh*_*Doe 18 c c++ performance c-libraries

我看到了这个链接,但我不是要求使用"extern"的代码性能下降.我的意思是没有"extern",在C++中使用C库时是否存在"上下文切换"? 在C++应用程序中使用纯C(非类包装)函数时是否有任何问题?

Bas*_*tch 36

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

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

实际上extern "C",不要更改任何调用约定,但禁用名称修改.但是,它对编译器的确切影响是特定于该编译器的.它可能(或不)禁用内联(但考虑-fltoGCC中的链接时优化).

某些C编译器(例如tinycc)会生成性能较差的代码.即使GCC,当用于-O0或不明确使优化(例如,通过传球 -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++异常更快,但它们没有相同的语义(请参阅堆栈展开),longjmp并且不能很好地融合C++代码.

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


上下文切换是与操作系统多任务相关的概念,发生在运行抢占期间可执行的机器代码的进程上.如何获取该可执行文件(来自C编译器,来自C++编译器,来自Go编译器,来自SBCL编译器,或者是其他语言(如Perl或字节码Python)的解释器)是完全无关紧要的(因为上下文切换可能发生)在任何机器指令,在中断期间).阅读一些书籍,如操作系统:三个Eeasy Pieces.

  • 我认为OP假设从C++跳转到C时可能会有堆栈切换,反之亦然.有时在从一种语言转换到另一种语言时需要这样做,而使用C和C++则不是这种情况.Go可能必须在执行外部C代码时以某种方式切换堆栈,因为它使用分段堆栈来执行协同程序,因此需要将特殊生成的代码插入到每个函数中 - 这对于典型的C库来说是不可行的. (3认同)
  • 他把"语境转换"放在引号中.我假设他指的是C++程序和C库之间的某种类型的thunking/proxy代码. (2认同)

Bee*_*ope 13

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

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

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

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

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


0有趣的是,链接时优化实际上允许在C++代码中内联 C方法,这是LTO的一个小问题.当然,这通常取决于使用适当的LTO选项从源代码构建C库.

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

2至少部分地减轻了这一事实,即许多C++标准库调用最终委托C库例程进行"大量"提升,例如如何std::copy调用memcpymemset何时可能以及大多数new实现最终调用的方式malloc.