简体   繁体   English

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

[英]Is there a performance degradation / penalty in using pure C library in C++ code?

I saw this link but I'm not asking for a performance degradation for code using "extern". 我看到了这个链接,但我不是要求使用“extern”的代码性能下降。 I mean without "extern", is there "context switching" when using C library in C++? 我的意思是没有“extern”,在C ++中使用C库时是否存在“上下文切换”? Are there any problems when using pure C (not class-wrapped) functions in C++ application? 在C ++应用程序中使用纯C(非类包装)函数时是否有任何问题?

Both C and C++ are programming language specifications (written in English, see eg n1570 for the specification of C11) and do not speak about performance (but about behavior of the program, ie about semantics ). C和C ++都是编程语言规范 (用英语编写,参见例如n1570,用于C11的规范)并且不谈论性能(但是关于程序的行为,即关于语义 )。

However, you are likely to use a compiler such as GCC or Clang which don't bring any performance penalty, because it builds the same kind of intermediate internal representation (eg GIMPLE for GCC, and LLVM for Clang) for both C and C++ languages, and because C and C++ code use compatible ABI s and calling conventions . 但是,您可能会使用诸如GCCClang之类的编译器,这些编译器不会带来任何性能损失,因为它为C和C ++语言构建了相同类型的中间内部表示(例如GCC的GIMPLE和Clang的LLVM)。 ,因为C和C ++代码使用兼容的ABI调用约定

In practice extern "C" don't change any calling convention but disables name mangling . 在实践中, extern "C"不会更改任何调用约定但禁用名称修改 However, its exact influence on the compiler is specific to that compiler. 但是,它对编译器的确切影响是特定于该编译器的。 It might (or not) disable inlining (but consider -flto for link-time-optimization in GCC). 它可能(或不)禁用内联 (但考虑-flto用于GCC中的链接时优化)。

Some C compilers (eg tinycc ) produce code with poor performance. 某些C编译器(例如tinycc )会生成性能较差的代码。 Even GCC or Clang , when used with -O0 or without explicitly enabling optimization (eg by passing -O1 or -O2 etc...) might produce slow code (and optimizations are by default disabled with it). 甚至GCCClang ,当与-O0或没有明确启用优化时 (例如通过传递 -O1-O2等...)可能会产生慢速代码(默认情况下,优化功能禁用)。

BTW, C++ was designed to be interoperable with C (and that strong constraint explains most of the deficiencies of C++). BTW,C ++被设计为可与C互操作(并且强约束解释了C ++的大多数缺陷)。

In some cases, genuine C++ code might be slightly faster than corresponding genuine C code. 在某些情况下,真正的C ++代码可能比相应的正版C代码快。 For example, to sort an array of numbers, you'll use std::array and std::sort in genuine C++, and the compare operations in the sort are likely to get inlined. 例如,要对数字数组进行排序,您将在正版C ++中使用std :: arraystd :: sort ,并且排序中的比较操作可能会被内联。 With C code, you'll just use qsort and each compare goes through an indirect function call (because the compiler is not inlining qsort , even if in theory it could...). 使用C代码,您只需使用qsort ,每次比较都会通过间接函数调用(因为编译器不会内联qsort ,即使理论上它可以......)。

In some other cases, genuine C++ code might be slightly slower; 在其他一些情况下,真正的C ++代码可能会稍微慢一点; for example, several (but not all) implementations of ::operator new are simply calling malloc (then checking against failure) but are not inlined. 例如, ::operator new几个(但不是全部)实现只是调用malloc (然后检查失败)但是没有内联。

In practice, there is no penalty in calling C code from C++ code, or C++ code from C code, since the calling conventions are compatible. 实际上,从C ++代码调用C代码或从C代码调用C ++代码没有任何代价,因为调用约定是兼容的。

The C longjmp facility is probably faster than throwing C++ exceptions, but they don't have the same semantics (see stack unwinding ) and longjmp doesn't mix well accross C++ code. C longjmp工具可能比抛出C ++异常更快,但它们没有相同的语义(请参阅堆栈展开 ),而longjmp并不能很好地融合C ++代码。

If you care that much about performance, write (in genuine C and in genuine C++) twice your code and benchmark. 如果你非常关心性能,那么在你的代码和基准测试中写两次(在真正的C和真正的C ++中)。 You are likely to observe a small change (a few percents at most) between C and C++, so I would not bother at all (and your performance concerns are practically unjustified). 您可能会观察到C和C ++之间的微小变化(最多几个百分点),所以我根本不会打扰 (而且您的性能问题实际上是不合理的)。


Context switch is a concept related to operating system and multitasking and happens on processes running machine code executable during preemption . 上下文切换是与操作系统多任务相关的概念,发生在运行抢占期间可执行的机器代码的 进程上。 How that executable is obtained (from a C compiler, from a C++ compiler, from a Go compiler, from an SBCL compiler, or being an interpreter of some other language like Perl or bytecode Python) is totally irrelevant (since a context switch can happen at any machine instruction, during interrupts ). 如何获取该可执行文件 (来自C编译器,来自C ++编译器,来自Go编译器,来自SBCL编译器,或者是其他语言(如Perl或字节码Python)的解释器)是完全无关紧要的(因为上下文切换可能发生)在任何机器指令,在中断期间)。 Read some books like Operating Systems: Three Eeasy Pieces . 阅读一些书籍,如操作系统:三个Eeasy Pieces

At a basic level, no , you won't see any type of "switching" performance penalty when calling a C library from C++ code. 在基本级别, ,当从C ++代码调用C库时,您将看不到任何类型的“切换”性能损失。 For example calling from C++ a C method defined in another translation unit should have approximately identical performance to calling the same method implemented in C++ (in the same C-like way) in another translation unit. 例如,从C ++调用另一个转换单元中定义的C方法应该具有与在另一个转换单元中调用C ++(以相同的C类方式)实现的相同方法大致相同的性能。

This is because common implementations of C and C++ compilers ultimately compile the source down to native code, and calling an extern "C" function is efficiently supported using the same type of call that might occur for a C++ call. 这是因为C和C ++编译器的常见实现最终将源代码编译为本机代码,并且使用与C ++调用可能发生的相同类型的call有效地支持调用extern "C"函数。 The calling conventions are usually based on the platform ABI and are similar in either case. 调用约定通常基于平台ABI,并且在任何一种情况下都类似。

That basic fact aside, there might still be some performance downsides when calling a C function as opposed to implementing the same function in C++: 除了基本事实之外,在调用C函数时可能仍然存在一些性能缺点,而不是在C ++中实现相同的函数:

  • Functions implemented in C and declared extern "C" and called from C++ code usually won't be inlined (since by definition they aren't implemented in a header), which inhibits a whole host of possibly very powerful optimization 0 . 用C和声明的extern "C"并从C ++代码调用的函数通常不会被内联(因为根据定义它们没有在头文件中实现),这会抑制整个主机可能非常强大的优化0
  • Most data types used in C++ code 1 can't be directly used by C code, so for example if you have a std::string in your C++ code, you'll need to pick a different type to pass it to C code - char * is common but loses information about the explicit length, which may be slower than a C++ solution. C代码1中使用的大多数数据类型都不能被C代码直接使用,因此,例如,如果您的C ++代码中有std::string ,则需要选择其他类型将其传递给C代码 - char *很常见,但丢失了有关显式长度的信息,这可能比C ++解决方案慢。 Many types have no direct C equivalent, so you may be stuck with a costly conversion. 许多类型没有直接的C等价物,因此您可能会遇到代价高昂的转换。
  • C code uses malloc and free for dynamic memory management, while C++ code generally uses new and delete (and usually prefers to hide those calls behind other classes as much as possible). C代码使用mallocfree进行动态内存管理,而C ++代码通常使用newdelete (并且通常更喜欢尽可能隐藏其他类后面的调用)。 If you need to allocate memory in one language that will be freed in other other, this may cause a mismatch where you need to call back into the "other" language to do the free, or may unnecessary copies, etc. 如果您需要使用一种将在其他语言中释放的语言分配内存,则可能会导致不匹配,您需要回拨“其他”语言来执行免费,或者可能不必要的副本等。
  • C code often makes heavy use of the C standard library routines, while C++ code usually uses methods from the C++ standard library. C代码经常大量使用C标准库例程,而C ++代码通常使用C ++标准库中的方法。 Since there is a lot of functional overlap, it is possible that a mix of C and C++ has a larger code footprint than pure C++ code since more C library methods are used 2 . 由于存在大量功能重叠,因此C和C ++的混合可能比纯C ++代码具有更大的代码占用空间,因为使用了更多的C库方法2

The concerns above would apply only when contrasting a pure C++ implementation versus a C one, and doesn't really mean there is a performance degradation when calling C: it is really answering the question "Why could writing an application in a mix of C and C++ be slower than pure C++?". 上述问题仅适用于纯C ++实现与C语言的对比,并不意味着在调用C时性能会下降:它实际上是在回答“为什么可以在C和C的混合中编写应用程序”的问题。 C ++比纯C ++慢?“ Furthermore, the above issues are mostly a concern for very short calls where the above overheads may be significant. 此外,上述问题主要是对非常短的呼叫的关注,其中上述开销可能很大。 If you are calling a lengthy function in C, it is less of a problem. 如果你在C中调用一个冗长的函数,那就不是问题了。 The "data type mismatch" might still bite you, but this can be designed around on the C++ side. “数据类型不匹配”可能仍然会让你感到厌烦,但这可以在C ++方面进行设计。


0 Interestingly, link-time optimization actually allows C methods to be inlined in C++ code , which is a little-mentioned benefit of LTO. 0有趣的是,链接时优化实际上允许在C ++代码中内联 C方法,这是LTO的一个小提到的好处。 Of course, this is generally dependent on building the C library yourself from source with the appropriate LTO options. 当然,这通常取决于使用适当的LTO选项从源代码构建C库。

1 Eg, pretty much anything other than a standard layout type. 1例如,除标准布局类型之外的其他任何东西。

2 This is at least partially mitigated by the fact that many C++ standard library calls ultimately delegate to C library routines for the "heavy" lifting, such as how std::copy calls memcpy or memset when possible and how most new implementations ultimately call malloc . 2许多C ++标准库调用最终委托给C库例程进行“重”提升,例如std::copy如何在可能的情况下调用memcpymemset以及大多数new实现最终如何调用malloc这至少部分地减轻了这一点。 。

C++ has grown and changed a lot since its inception, but by design it is backwards-compatible with C. C++ compilers are generally built from C compilers, but even more modernized with link-time optimizations . C ++从一开始就发展和变化很多,但是在设计上它与C语言向后兼容.C ++编译器通常是用C编译器构建的,但是通过链接时优化更加现代化。 I would imagine lots of software can reliably mix C and C++ code, both in the user spaces and in the libraries used. 我认为很多软件可以在用户空间和使用的库中可靠地混合使用C和C ++代码。 I answered a question recently that involved passing a C++ class member function pointer, to a C-implemented library function. 我最近回答了一个问题 ,涉及将C ++类成员函数指针传递给C实现的库函数。 The poster said it worked for him. 海报说这对他有用。 So it's possible C++ is more compatible with C than any programmers or users would think. 因此,C ++与C语言的兼容性可能超过任何程序员或用户的想法。

However, C++ works in many different paradigms that C does not, as it is object-oriented, and implements a whole spectrum of abstractions, new data types, and operators. 但是,C ++在许多不同的范例中工作,因为它是面向对象的,并且实现了整个范围的抽象,新数据类型和运算符。 Certain data types are easily translatable ( char * C string to a std::string ), while others are not. 某些数据类型很容易翻译( char * C string到std::string ),而其他数据类型则不然。 This section on GNU.org about C++ compiler options may be of some interest. 有关C ++编译器选项的GNU.org上的这一部分可能会引起一些兴趣。

I would not be too worried or concerned about any decline in performance, when mixing the two languages. 混合这两种语言时,我不会太担心或担心性能下降。 The end user, and even the programmer, would hardly notice any measurable changes in performance, unless they were dealing with big abstractions of data. 最终用户,甚至程序员,几乎都不会注意到性能的任何可测量的变化,除非他们处理的是大数据抽象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM