我看到了这篇文章,但我并不是在询问使用“extern”会导致代码性能下降的问题。我的意思是,在C++中使用C库时,如果没有使用“extern”,是否存在“上下文切换”?
在C++应用程序中使用纯C(非类封装)函数会有什么问题吗?我看到了这篇文章,但我并不是在询问使用“extern”会导致代码性能下降的问题。我的意思是,在C++中使用C库时,如果没有使用“extern”,是否存在“上下文切换”?
在C++应用程序中使用纯C(非类封装)函数会有什么问题吗?C和C++都是编程语言的规范(用英语编写,例如参见n1570中的C11规范),它们不涉及性能问题(而是关于程序的行为,即semantics)。
然而,您可能会使用像GCC或Clang这样的编译器,它们不会带来任何性能损失,因为它们为C和C ++语言构建相同类型的中间内部表示(例如GCC的GIMPLE和Clang的LLVM),并且因为C和C ++代码使用兼容的ABI和calling conventions。
在实践中,extern "C"
不会改变任何调用约定,但会禁用name mangling。然而,它对编译器的确切影响取决于该编译器。它可能(也可能不)禁用inlining(但在GCC中考虑使用-flto
进行链接时优化)。
一些C编译器(例如tinycc)生成的代码性能较差。即使使用GCC或Clang,当使用-O0
或未明确启用optimization(例如通过passing -O1
或-O2
等...)时,也可能会产生缓慢的代码(并且默认情况下禁用优化)。
顺便提一下,C++旨在与C互操作(这个强约束解释了C++的大多数不足之处)。
在某些情况下,真正的C++代码可能会比相应的真正的C代码稍微快一些。例如,要对数字数组进行排序,您将在真正的C++中使用std::array和std::sort,并且排序中的比较操作很可能会被内联。对于C代码,您将只使用qsort,每个比较都通过间接函数调用进行(因为编译器没有内联qsort
,即使在理论上它可以...)。::operator new
的实现只是调用malloc
(然后检查失败),但没有被内联。longjmp
在C++代码中不太适用。上下文切换是与操作系统和多任务处理相关的概念,在进程在抢占期间运行机器码可执行文件时发生。如何获得可执行文件(从C编译器、C++编译器、Go编译器、SBCL编译器或作为某种语言的解释器,如Perl或字节码Python)都是完全无关紧要的(因为上下文切换可以在任何机器指令中,在中断期间发生)。阅读一些书籍,比如操作系统:三个简单部分。
::operator new
的实现只是调用malloc
而没有内联。情况可能比这更糟:在我的机器上,一个实现为通过调用malloc()
来调用::operator new()
的函数比标准的::operator new()
每次调用快大约一百个CPU周期... - cmaster - reinstate monica基本上来说,从C++代码调用C库时,你不会看到任何类型的"切换"性能惩罚。不会有性能损失。例如,从C++中调用在另一个翻译单元中定义的C方法,与在另一个翻译单元中以相同的C方式实现的C++中调用相同的方法应该具有大致相同的性能。
这是因为常见的C和C++编译器实现最终将源代码编译成本地代码,并使用与C++调用可能发生的相同类型的call
高效支持调用extern "C"
函数。调用约定通常基于平台ABI,在任一情况下都是类似的。
除了这个基本事实之外,调用C函数而不是在C++中实现相同函数仍可能存在一些性能缺陷:
extern "C"
的函数通常不会被内联(因为按定义它们不是在头文件中实现的),这抑制了许多可能非常强大的优化0。std::string
,则需要选择不同的类型将其传递给C代码-char*
很常见,但会丢失关于显式长度的信息,这可能比C++解决方案慢。许多类型没有直接的C等价物,因此您可能会陷入昂贵的转换中。malloc
和free
进行动态内存管理,而C++代码通常使用new
和delete
(并且通常更喜欢将这些调用隐藏在其他类后面)。如果您需要在一种语言中分配将在另一种语言中释放的内存,则可能会导致不匹配,需要回调到“其他”语言进行释放,或者可能会出现不必要的副本等情况。0 有趣的是,链接时优化实际上允许将C方法内联到C++代码中,这是LTO很少提到的好处。当然,这通常取决于使用适当的LTO选项从源代码构建C库。
1 例如,几乎任何非标准布局类型。
2 这至少部分地得到缓解,因为许多C ++标准库调用最终会委托给C库例程来处理“重”工作,例如std :: copy
在可能时调用memcpy
或memset
以及大多数new
实现最终调用malloc
.
C++自诞生以来已经发生了很多变化,但是它的设计使它与C向后兼容。C++编译器通常是从C编译器构建而成的,但是更加现代化,具有链接时优化。我想很多软件都可以可靠地混合使用C和C++代码,无论是在用户空间还是在使用的库中。最近我回答了一个问题,涉及将C++类成员函数指针传递给一个由C实现的库函数。发帖者说它对他有效。因此,C++可能比任何程序员或用户想象的更兼容C。
然而,C++ 的范式比 C 更多,因为它是面向对象的,并实现了整个抽象、新数据类型和运算符的光谱。某些数据类型易于转换(从char *
C 字符串到 std::string
),而其他数据类型则不然。GNU.org 上关于 C++ 编译器选项的本节 可能会引起一些兴趣。
extern
关键字,你的意思是什么?如果C++中没有以某种方式声明为extern "C"
,那么你是如何从C++中调用C函数的? - BeeOnRope