We have a large project with C and C++ code.
For every C++ implementation, apart from the C++ header, we usually have provide a C-header to allow functionality to be available for .c files, also.
So, most of our files look like so:
foo.hpp:
class C {
int foo();
};
foo.h:
#ifdef __cplusplus
extern "C" {
typedef struct C C; // forward declarations
#else
class C;
#endif
int foo( C* ); // simply exposes a member function
C* utility_function( C* ); // some functionality *not* in foo.hpp
#ifdef __cplusplus
}
#endif
foo.cpp:
int C::foo() { /* implementation here...*/ }
extern "C"
int foo( C *p ) { return p->foo(); }
extern "C"
C* utility_function ( C* ) { /* implementation here...*/ }
QUESTION:
Suppose I wanted to add a namespace to the class like so:
foo.hpp:
namespace NS {
class C {
int foo();
};
}
what is the best scheme to follow in the C-headers?
I have considered a few options, but I'm looking for the most elegant, safe and easy to read. Is there a standard way you use?
Here are the options I've considered:
(I've ommitted the extern "C"
constructs for simplicity)
- Option 1: fool the compiler by adding some code in each header:
foo.h
#ifdef __cplusplus
namespace NS { class C; } // forward declaration for C++
typedef NS::C NS_C;
#else
struct NS_C; // forward declaration for C
#endif
int foo( NS_C* );
NS_C* utility_function( NS_C* );
this adds some complexity to the header, but keeps the implementations unchanged.
Option 2: Wrap the namespace with a C-struct:
Keeps the header simple but makes the implementation more complex:
foo.h
struct NS_C; // forward declaration of wrapper (both for C++ and C)
int foo( NS_C* );
NS_C* utility_function( NS_C* );
foo.cpp
namespace NS {
int C::foo() { /* same code here */ }
}
struct NS_C { /* the wrapper */
NS::C *ptr;
};
extern "C"
int foo( NS_C *p ) { return p->ptr->foo(); }
extern "C"
NS_C *utility_function( NS_C *src )
{
NS_C *out = malloc( sizeof( NS_C ) ); // one extra malloc for the wrapper here...
out->ptr = new NS::C( src->ptr );
...
}
are these the only schemes? Are there any hidden disadvantages in any of these?