c++csoftware-designlibrary-design

Compose C header file to be able to be used from C++


I'm working on some library header file that is supposed to be used from both C and C++. Since C does not have a namespace concept I would add a "library prefix" to all names defined in the header file. By contrast, for C++ I would define a namespace. So I currently think of the design as something like this:

mylib.h

#ifdef __cplusplus
namespace mylib{
#define NAME_PREFIX(identifier) identifier
extern "C" {
#else
#define NAME_PREFIX(identifier) mylib_identifier
#endif

int NAME_PREFIX(foo)(void);

//other declarations go here

#ifdef __cplusplus
} //extern "C"
} //namespace mylib
#endif

I have never seen something like that so I am not sure if that is common. Is it discouraged to do so? What are possible drawbacks?


Solution

  • So, as I mentioned in the comments, there are three problems I see with this approach.

    First, it does not allow the library to be used with mixed C/C++ translation if any entities are supposed to share linkage between the two languages. If the header file is included in a C translation unit and a C++ translation unit, all declared entities will have different names, either with a prefix or without one. So in effect it will work out as if these were two separate libraries, one used in the C translation unit and one in the C++ translation unit. If any library entities are supposed to share linkage between the translation units, it won't work.

    Second, extern "C" inside the namespace will scope the name properly inside the namespace for C++ code. However, in order to guarantee C linkage, the name without namespace prefix must be introduced into the global C namespace, cluttering it with lots of names without a library prefix.

    Third, it makes it difficult to write user code that should be translatable between C and C++ as well. Any such user would have to introduce a similar macro.

    If the library is not supposed to be used in mixed C/C++ code (or without any shared linkage), then extern "C" is unnecessary and after removing it, I think the approach may be fine.