9

I'm developing a software which is in C++ but that communicates with a C app through a shared header file containing the communication protocol. Since C is "more basic" than C++, I always need to write the header in C code (so C++ also gets it); otherwise it wouldn't work for the second app.

The problem is that I need to use a scope-quilifier such as the C++ namespaces - which don't exist in C.

What are all the options to emulate the namespace feature in C?

The only possibility I have seen so far is the one shown in this SO question, but unfortunately the answer is not clear enough and I would certainly like to know if there are other options. I also tried to use structs to do the job, without success (at least considering a struct with an enumerator).

Community
  • 1
  • 1
Momergil
  • 2,213
  • 5
  • 29
  • 59
  • 1
    Don't emulate it at all. Use `#ifdef __cplusplus` to determine whether you are included by C++ sources, and add namespacing and `extern "C"` than. You might even put the declaration into an inner `internal`-namespace and use `using prefix_free_name = internal::long_prefix_laden_c_name;` in the outer public namespace. – Deduplicator Aug 21 '14 at 17:30
  • @Deduplicator Thanks for the reply. I'm not sure, though, if I understood your suggestion - I know the `__cplusplus` thing and `extern "C"` separately, but not as a solution the scope problem I posted in my question. Could you give me an implementation example? – Momergil Aug 21 '14 at 17:33
  • Just have a naming convention, e.g. like GTK where every C name is starting with `Gtk` (or `_Gtk` for `struct` tags).... – Basile Starynkevitch Aug 21 '14 at 17:52
  • @BasileStarynkevitch well actually I have naming convention already inplemented in structs, defines and the name of the enums - but not the enums content. And here is where the absence of namespace are giving me problems. But even if I do use naming conventions even for the content of enums, I'ld still have the curiosity of knowing my possibilities :) – Momergil Aug 21 '14 at 18:08

4 Answers4

12

You can hide all of your exported functions from being exported from the module with static at the definition level, so that no names are placed in the global space, and instead put them in a struct that is the only thing provided by the module.

E.g. foo.h:

struct ns_t {
    int (*a)(int, int);
    void (*b)(float, float);
};
extern struct ns_t ns;

foo.c:

#include "foo.h"

static int a(int x, int y) {
    ...
}

static void b(float x, float y) {
    ...
}

struct ns_t ns = { .a = a, .b = b };

bar.c:

#include "foo.h"
....
ns.b(4.5, 6.8);
....
Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
  • thanks for the reply. Is it possible to do all of this code inside a header file only? – Momergil Aug 21 '14 at 17:38
  • 1
    You can't prevent anything in a header file from being visible to the code that includes it, in C, although I guess you could always give the function definitions themselves extremely ungainly names to prevent accidental usage? It's not normal to put definitions in the header in C though. Doesn't work like C++. – Alex Celeste Aug 21 '14 at 17:41
  • 6
    That's an interesting take on namespaces. Though there's probably a bad effect on performance, due to always jumping through those global pointers... – Deduplicator Aug 21 '14 at 17:44
  • "Doesn't work like C++".. you can't put function defintions in the header in C++ unless it's a template. Unless of course you love bloat and compiler errors about function redefinition. – Brandon Aug 21 '14 at 17:57
  • I meant within classes. I'm not much of a C++er but I think it is normal for class definitions in headers to include code too, which won't cause any duplication errors thanks to compiler cleverness, right? And of course templates themselves. – Alex Celeste Aug 21 '14 at 17:59
  • Only very small class functions would go in the header/declaration. It inlines them that's why. So it will make the executable considerably larger and compiling will take WAY longer. I used to think that way too but I asked here: https://www.daniweb.com/software-development/cpp/threads/423106/separate-headers-from-source and the answer was "don't do it". lol. – Brandon Aug 21 '14 at 18:01
7

Don't emulate namespaces in C at all, go the C way:

  • Use prefixes instead of namespaces.
  • Use suffixes instead of overloading.
    • Optionally use a macro with _Generic to simulate overloading on argument-types.

Your include file should define those C functions in an inner detail-namespace for C++ (does not change the functions actual identity, due to C-linkage), and then you strip prefixes and suffixes from the C functions for C++.
It looks like this:

#ifndef MY_HEADER_GUARD_unique_suffix
#define MY_HEADER_GUARD_unique_suffix
#ifdef __cplusplus
namespace my_module {
namespace detail {
extern "C" {
#endif
// Defines for common structs and functions here
// Also inline functions written in the common intersection of C and C++
#ifdef __cplusplus
}
}
using init = detail::my_module_init;
using close = detail::my_module_close;
}
#endif
#endif

You might also want to add member-functions to some of the C structs for the C++ interface, which might be inline-functions delegating to a shared function.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • thanks for the answer. Although it doesn't answer my question, it does provide an interesting suggestion for my particular problem (at least from the view of the C++ app; the C app would still lack a `namespace` equivalence). My only doubt is the significance of those two last lines (`using init` and `using close`): what are they for? – Momergil Aug 21 '14 at 18:18
  • 3
    @Momergil: They are for stripping any prefixes (C alternative to namespaces) and suffixes (C alternative to overloading). BTW: You can use `_Generic` to provide an interface without suffixes in C). – Deduplicator Aug 21 '14 at 20:03
2

First, you start out by prefixing all exported symbols (including names of preprocessor defines and enum members) with a namespace. For example, you could have a function declaration

void foo_bar_baz(void);

On the C++ side, these need to be wrapped in extern "C" { … } and then should be registered with the correct namespace. Assuming C++11, in case of functions this should be as simple as

namespace foo {
    namespace bar {
        constexpr auto baz = foo_bar_baz;
    }
}

On the C side, you could define shortened names like

#define baz foo_bar_baz

use compiler-specific attributes to register an alias or add a constant declaration

static void (*const baz)(void) = foo_bar_baz;

This works out just fine because calling a function actually makes use of function pointers (instead of designators).

You could put everything into a single header with some #ifdefs as appropriate, or you could provide small wrappers like foo/bar.hxx for C++ and foo/bar-import.h for shortened C names in addition to foo/bar.h which contains the actual prefixed declarations and would be included by the other headers.

Christoph
  • 164,997
  • 36
  • 182
  • 240
0

I've been working on a system that very much depend on namespaces (build-type inserted-ones that is), and from my looking at C, you can imperfectly emulate C++ namespaces (on Linux anyway) by collecting the symbols your exports for static linking, prefixing them with objcopy and then macro-translating your header code (excluding includes) to match the prefixed symbol set.

The problem with this is that macros don't respect scope and so assuming your library exports void foo() (or symbol foo in short) -- and you'd prefix that into mylib_foo, then a macro that translates foo into mylib_foo would also indiscriminately translate struct members named foo even though those should not be translated.

I believe that doing it right would actually require hacking at the compiler (and somebody do it please! :)).

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142