Compilation of this example:
gcc -c -D NAMESPACE=First_ first.c -o First_first.o
gcc -c -D NAMESPACE=Second_ second.c -o Second_second.o
gcc -c -D NAMESPACE=Third_ third.c -o Third_third.o
gcc -c -D NAMESPACE=Fourth_ fourth.c -o Fourth_fourth.o
gcc -c -D NAMESPACE=FirstAgain_ first.c -o FirstAgain_first.o
gcc -c -D NAMESPACE=SecondAgain_ second.c -o SecondAgain_second.o
gcc -c main.c -o main.o
gcc main.o First_first.o Second_second.o Third_third.o Fourth_fourth.o FirstAgain_first.o SecondAgain_second.o -o main.exeThere are limitations with this namespacing macro pattern!
Firstly we rely on #pragma once for our headers. This is because inclusion
guard macros cannot be namespaced. Macro identifiers are always literal, it is
impossible to define a macro identifier from an expression. Thus using inclusion
guards would result in namespace pollution, which is what we're trying to avoid
with this namespacing pattern. If we allowed inclusion guards, that would defeat
the point of using this namespacing pattern! Note that #pragma once relies on
file characteristics and file path, whereas inclusion guards rely on a unique
macro constant.
Ideally we would have preferred using something like:
#ifndef NS(FILE_H)
#define eval(NS(FILE_H))
// ...
#endifWe need something to disambiguate #define NS(FILE_H), does it mean to define
NS() macro expression again, or does it mean to evaluate NS(FILE_H) and use
the resulting value as the new macro identifier?
The #pragma once has wide support: https://en.wikipedia.org/wiki/Pragma_once#Portability
Beware there are big caveats with #pragma once:
With or without #pragma once in our header files, header files that include
included header files can result in namespace conflicts. The namespace conflicts
occur in opposite ways.
With #pragma once, when a header file that includes an included header file,
and sets a different namespace from the prior inclusion for the current
inclusion, a compilation failure can occur because the current inclusion will
be not be included. The solution is to make all inclusions of a particular
header file use the same namespace.
Without #pragma once, when a header file that includes an included header file,
and sets the same namespace for the current inclusion that was used in the prior
inclusion, a compilation failure can occur due to multiple definitions caused
by multiple inclusion. The solution is to make all inclusions of a particular
header file use different namespaces.
Out of the 2 above situations, which is the more desirable? I'd argue the former should be preferred from the latter. The latter forces you compile a separate namespaced object file for linking, for every repeated inclusion. This is pretty inefficient! The former situation allows empty namespaced libraries to be included normally without any problems. Only once you meet a namespace clash with a empty namespace, do you consider adding a custom namespace. At this point you just need to remember that this custom namespace should be applied to every inclusion of the same library.
So just remember, don't namespace (just means leave the namespace empty) until you need it. It will reduce headaches under repeated nested inclusion.
Note that the above mentioned problem does not apply to separate compilation of object files. Each object file can be compiled from the same libraries with different or the same namespace without any problems. They are later just linked together. However for efficiency reasons, it may be better for all the linked objects to standardise on the namespace.
Secondly we rely on #pragma push_macro and #pragma pop_macro for libraries
that need their own namespace while namespacing their own dependencies. This is
required because the preprocessor doesn't perform imperatively. See:
- http://stackoverflow.com/questions/14261534/temporarily-overwrite-a-macro-in-c-preprocessor
- http://stackoverflow.com/questions/1543736/how-do-i-temporarily-disable-a-macro-expansion-in-c-c
Ideally we would have preferred using "temporary macro variables":
#define THIS_NAMESPACE NAMESPACE
// ...
#define NAMESPACE THIS_NAMESPACEWhich should be the equivalent of:
var x = y;
y = x;
But it doesn't work because the C preprocessor is globally declarative, not imperative.
The #pragma push_macro and #pragma pop_macro only works in MSVC, GCC and
Clang.
I could never reconcile having to write a file full of
#define NAMESPACE ...commands in it, and keep that synchronized with whatever the heck build system I'm using that has to specify-DNAMESPACE=.... I thought about making a namespace definition language, which those two things could be derived from in whatever the heck build system I'm using, but at that point why not simply translate the C source code itself?So in the end, I think it best to specify a hardcoded namespace like
int first_addone(int x) { return x + 1; }and then optionally putting both the .h and the .c through a text filter substituting 'first_' for 'firstagain_' in the build process, to generate the re-namespaced code. It also takes care of any macros namedFIRST_WHATEVER(...)if you match case insensitively, including guard macros, and it can go into a file named 'firstagain.h' so that other modules which#includeit will be able to visually specify what they mean byfirstagain_addone(41)Maybe you could even transform those other modules, also swapping
#include "first.h"for#include "firstagain.h", so their code could use the first "first_" module while yours used a second one. That's kind of getting too complicated for me to really comprehend the consequences though.