我看到了这个链接,但我不是要求使用“extern”的代码性能下降。我的意思是没有“extern”,在C ++中使用C库时是否存在“上下文切换”? Are there any problems when using pure C (not class-wrapped) functions in C++ application?
答案 0 :(得分:36)
C和C ++都是编程语言规范(用英文编写,参见例如n1570的C11规范)并且不谈性能(但是关于程序的行为,即约semantics)。
但是,您可能会使用GCC或Clang之类的编译器,这些编译器不会带来任何性能损失,因为它构建了相同类型的中间内部表示(例如,GCC的GIMPLE, C语言和C ++语言,以及C和C ++代码使用兼容的ABI和calling conventions。
实际上extern "C"
不会更改任何调用约定但会禁用name mangling。但是,它对编译器的确切影响是特定于该编译器的。它可能(或不)禁用inlining(但在GCC中考虑-flto
进行链接时优化。)
某些C编译器(例如tinycc)会生成性能较差的代码。甚至GCC或Clang,与-O0
一起使用或明确启用optimization时(例如passing -O1
或-O2
等...)可能会生成慢速代码(默认情况下禁用优化)。
在某些情况下,正版C ++代码可能比相应的正版C代码略快。例如,要对数字数组进行排序,您将在正版C ++中使用std::array和std::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 system和multitasking相关的概念,在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 ++中实现相同的函数:
extern "C"
并且从C ++代码调用的函数通常不会被内联(因为根据定义它们没有在头文件中实现),这会抑制整个主机可能非常强大的优化< SUP> 0 std::string
,则需要选择一种不同的类型将其传递给C代码 - char *
很常见,但会丢失有关显式长度的信息,这可能比C ++解决方案慢。许多类型没有直接的C等价物,因此您可能会遇到代价高昂的转换。malloc
和free
进行动态内存管理,而C ++代码通常使用new
和delete
(并且通常更喜欢隐藏其他类后面的调用尽可能)。如果你需要用一种语言分配内存,而这种语言将在其他语言中被释放,这可能会导致你不需要回拨“其他”语言来做免费,或者可能不必要的副本等。上述问题仅适用于纯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可能会引起一些兴趣。
混合两种语言时,我不会太担心或担心性能下降。最终用户,甚至程序员,几乎都不会注意到性能上有任何可测量的变化,除非他们处理大量的数据抽象。