关于 C 和 C++ 编码标准的最佳实践是什么?是否应允许开发人员随意将它们混合在一起。链接 C 和 C++ 目标文件时是否有任何复杂情况。
传统上用 C 编写的套接字库之类的东西是否应该保留在 C 中并保存在单独的源文件中?就是将 c 代码保存在 .c 文件中,将 c++ 代码保存在 .cpp 文件中。在用 g++ 解析后混合 c 和 C++ 时会不会有任何性能损失,因为 C 中没有进行类型安全检查?但在 C++ 中。将是链接 C 和 C++ 源代码文件的最佳方式。
最大的问题是从 C++ 代码调用 C 函数,反之亦然。在这种情况下,您要确保使用 . 将函数标记为具有“C”链接extern "C"
。您可以直接使用以下方法在头文件中执行此操作:
#if defined( __cplusplus )
extern "C" {
#endif
extern int myfunc( const char *param, int another_one );
#if defined( __cplusplus )
}
#endif
您需要#if
s 因为包含它的 C 代码将无法理解extern "C"
。
如果您不想(或不能)更改头文件,可以在 C++ 代码中进行:
extern "C" {
#include "myfuncheader.h"
}
您可以以相同的方式将 C++ 函数标记为具有 C 链接,然后您可以从 C 代码中调用它。您不能对重载函数或 C++ 类执行此操作。
除此之外,混合 C 和 C++ 应该没有问题。我们有许多几十年前的 C 函数仍然被我们的 C++ 代码使用。
人们通常应该假设 c++ 可以抛出异常,因此块中的 c 包装函数应该捕获它们,并将它们转换为 c 调用者可以消化的漂亮错误代码。
extern "c"
{
int nice_c_function_interface
(
void
)
{
int returnStatus;
try
{
returnStatus = nice_cpp_function();
}
catch (NiceCppException& that)
{
returnStatus = that.failure_code();
}
catch (...)
{
cerr << "Oh Worse! an unexpected unknown exception" << endl;
returnStatus = -1; // Horrible unknown failure
}
return returnStatus;
}
}
C++ 不会在运行时进行“类型安全检查”,除非您要求(通过使用dynamic_cast
)。C++ 与 C 高度兼容,因此您可以随意调用 C 库并使用 C++ 编译器编译 C 代码。C++ 并不意味着“面向对象”,您应该不会因为使用它而受到性能损失。
如果您混合使用 gcc 和 g++ 编译的代码,请参阅 Graeme 的答案。
如果您在 C++ 中有一个函数调用 C 中的一个函数,该函数又调用 C++ 中的另一个函数,而后面的函数抛出一个应该被第一个函数捕获的异常,则除非您告诉 C 编译器启用,否则您可能会遇到问题异常处理表的生成。
对于 gcc,这是-fexceptions
参数,默认情况下为 C++ 启用,但默认为 C 禁用。
这里没有好的硬性规定。
如果最终产品将始终与 C++ main() 链接,那么这并不重要。因为您总是可以创建可以做正确事情的标题。
如果您正在创建一个需要具有 C 和 C++ 接口但您不能假定 C++ 链接器的库,那么您将需要确保将 C API 与 C++ 完全分离。在这一点上,在 C 中完成所有工作并使用 C++ 类代理到 C 通常更简洁。
例如:
/* c header */
struct CData
{ /* stuff */ };
void init( CData* data );
void fini( CData* data );
int getSomething( CData* data );
void doSomething( CData* data, int val );
// c++ header
extern "C" {
#include cdata.h
};
class CppData : private CData
{
public:
CppData() { ::init( (CData*)this ); }
~CppData() { ::fini( (CData*)this ); }
int getSomething() { return ::getSomething( (CData*)this ); }
void doSomething( int val ) { :: doSomething( (CData*)this, val ); }
};
我希望这有帮助。
如果您使用 g++ 编译所有源代码,那么所有源代码都将在 C++ 目标文件中编译(即使用适当的名称 mangling 和 C++ ABI)。
如果您正在构建需要由需要使用 C ABI 的显式 C 应用程序使用的库,则只需要使用 extern "C" 技巧。
如果所有内容都被编译为单个可执行文件,则使用 g++ 并将所有内容视为 C++