C和C ++编码标准

时间:2008-11-12 11:48:05

标签: c++ c standards

关于C和C ++编码标准的最佳做法是什么?应该允许开发人员不知所措地将它们混合在一起。链接C和C ++目标文件时是否存在任何复杂情况。

传统上用C语言编写的套接字库是否应保留在C中并保存在单独的源文件中?这是将.c文件和c ++代码中的c代码保存在.cpp文件中。 在使用g ++解析后混合c和C ++会有任何性能损失,因为类型安全检查不是在C中完成的吗?但是在C ++中。这将是链接C和C ++源代码文件的最佳方式。

6 个答案:

答案 0 :(得分: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 ++代码仍在使用它们。

答案 1 :(得分:3)

C ++不会在运行时执行'类型安全检查',除非您要求它们(使用dynamic_cast)。 C ++与C高度兼容,因此您可以根据需要自由调用C库,并使用C ++编译器编译C代码。 C ++并不意味着“面向对象”,使用它不会对性能造成任何损失。

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

答案 2 :(得分: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;
    }
}

答案 3 :(得分:1)

如果你在C ++中有一个函数调用C中的一个函数,而C函数又调用C ++中的另一个函数,后面这个函数会引发一个应该被第一个函数捕获的异常,除非你告诉C,否则你会遇到问题编译器,用于生成异常处理表。

对于gcc,这是-fexceptions参数,默认情况下为C ++启用,但默认情况下对C禁用。

答案 4 :(得分: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 ); }
 };

我希望这会有所帮助。

答案 5 :(得分:0)

如果使用g ++编译所有源代码,那么它全部用C ++目标文件编译(即使用适当的名称mangling和C ++ ABI)。

如果要构建需要使用C ABI的显式C应用程序需要使用的库,则只需要使用extern“C”技巧。

如果所有内容都被编译成单个可执行文件,那么使用g ++并将所有内容视为C ++