tags:

views:

719

answers:

6

What are best practices with regards to C and C++ coding standards? Should developers be allowed to willy-nilly mix them together. Are there any complications when linking C and C++ object files.

Should things like socket libraries that traditionally is written in C remain in C and kept in seperate source files? That is keeping c code in .c files and c++ code in .cpp files. When mixing c and C++ after being parsed with g++ will there be any performance penalties, since typesafe checks are not done in C? but are in C++. Would would be the best way to link C and C++ source code files.

+7  A: 

The biggest issue is calling a C function from C++ code or vice versa. In that case, you want to make sure you mark the function as having "C" linkage using extern "C". You can do this in the header file directly using:

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

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

#if defined( __cplusplus )
}
#endif

You need the #ifs because C code that includes it won't understand extern "C".

If you don't want to (or can't) change the header file, you can do it in the C++ code:

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

You can mark a C++ function as having C linkage the same way, and then you can call it from C code. You can't do this for overloaded functions or C++ classes.

Other than that, there should be no problem mixing C and C++. We have a number of decades-old C functions that are still being used by our C++ code.

Graeme Perrow
+2  A: 

C++ doesn't do 'typesafe checks' at run time unless you ask for them (by using dynamic_cast). C++ is highly compatible with C, so you may freely call C libraries as you wish and compile C code with a C++ compiler. C++ does not imply 'object-oriented', and you should get no performance penalty from using it.

If you mix code compiled with gcc and with g++, see Graeme's answer.

Sunlight
Just a detail, but a C++ compiler will compile C with a built-in C compiler. There are a few things that C does differently from C++.
tloach
Oh yes. I think, though, that the OP is referring to structured, calling-functions-style code as "C code", and my point was that that style is "C++ code" as well; since there's no penalty to using C++, one might as well not worry about the difference and do everything in C++ (not necessarily OOP!).
Sunlight
A: 

If you compile all your source with g++ then it is all compiled in C++ object files (i.e. with the appropriate name mangling and the C++ ABI).

You will only need to use the extern "C" trick if you are building libraries that need to be used by explicitly C applications that need to use the C ABI.

If everything is being compiled into a single executable then use g++ and treat everything as C++

Martin York
+1  A: 

If you have a function in C++ which calls a function in C which in turn calls another function in C++, and this later function throws an exception which should be caught by the first function, you can have problems unless you told the C compiler to enable generation of the exception handling tables.

For gcc, this is the -fexceptions parameter, which is enabled by default for C++ but disabled by default for C.

CesarB
+1  A: 

There are no good hard and fast rules here.

If the end product will always be linked with a C++ main() then it does not really matter. As you can always create headers that will do the correct thing.

If you are creating a library that needs to have a C and C++ interface but you can't assume the C++ linker then you will need to make sure you separated the C API from the C++ cleanly. At this point it is usually cleaner to do all the work in C and use C++ classes to proxy to the C.

For example:

/* 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 ); }
 };

I hope this helps.

David Allan Finch
+1  A: 

One should generally assume that c++ can throw exceptions, hence the c wrapper functions in your block, ought to catch them, and morph them into nice error codes that the c caller can digest.

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;
    }
}
EvilTeach