C 和 C++ 编码规范

8
什么是关于C和C++编码标准的最佳实践?开发人员是否允许随意混合它们?在链接C和C++对象文件时是否存在任何复杂性?
像传统上用C编写的套接字库这样的东西是否应该保留在C中,并保持在单独的源文件中?也就是说,将C代码保存在.c文件中,将C++代码保存在.cpp文件中。在使用g++解析后混合C和C++时,是否会有任何性能惩罚,因为在C中不进行类型安全检查,但在C++中进行了检查?什么是连接C和C++源代码文件的最佳方法?
6个回答

7

最大的问题是在C++代码中调用C函数或反过来。在这种情况下,您需要确保使用extern "C"将该函数标记为具有"C"链接。您可以直接在头文件中使用以下内容进行操作:

#if defined( __cplusplus )
extern "C" {
#endif

extern int myfunc( const char *param, int another_one );

#if defined( __cplusplus )
}
#endif

你需要使用#if,因为包含它的C代码无法识别extern "C"

如果你不想(或者不能)改变头文件,你可以在C++代码中实现:

extern "C" {
#include "myfuncheader.h"
}

您可以使用相同的方式将C++函数标记为具有C语言链接,然后可以从C代码中调用它。但是,您无法对重载函数或C++类执行此操作。

除此之外,混合使用C和C++应该没有问题。我们有许多几十年历史的C函数仍然被我们的C++代码使用。


3

除非您使用 dynamic_cast,否则C++在运行时不会进行“类型安全检查”。C++与C高度兼容,因此您可以自由地调用C库并使用C++编译器编译C代码。C++并不意味着“面向对象”,因此使用它不应导致性能损失。

如果您混合使用gcc和g++编译的代码,请参考Graeme的回答。


只是一个细节,但是C++编译器将使用内置的C编译器编译C代码。C语言在某些方面与C++有所不同。 - tloach
哦,是的。我认为,OP指的是结构化、调用函数风格的代码被称为“C代码”,而我的观点是这种风格也是“C++代码”;由于使用C++没有任何惩罚,因此最好不要担心差异,一切都可以用C++完成(不一定是面向对象编程!)。 - Sunlight

3

通常应该假设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;
    }
}

1
如果你在C++中有一个函数,它调用了C中的一个函数,而这个C函数又调用了另一个C++函数,后者抛出了一个异常,应该被第一个函数捕获,那么你可能会遇到问题,除非你告诉C编译器启用异常处理表的生成。
对于gcc来说,这是-fexceptions参数,默认情况下对于C++启用,但对于C禁用。

1

这里没有什么好的硬性规定。

如果最终产品总是与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 ); }
 };

希望这能有所帮助。


0
如果您使用g++编译所有源代码,则所有内容都将编译为C++对象文件(即具有适当的名称重整和C++ ABI)。
只有在构建需要由显式使用C ABI的C应用程序使用的库时,才需要使用extern "C"技巧。
如果所有内容都被编译为单个可执行文件,则使用g++并将所有内容视为C++。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接