That does not work for types and constants.
It doesn't matter because these things do not have linkage. Clashes
among names that don't have any sort of pervasive scope such as external
linkage can be solved with a local renaming.
E.g. two library header files define "struct foo". No problem.
#define foo abc_foo
#include "abclib.h"
#undef foo
#define foo xyz_foo
#include "xyzlib.h"
#undef foo
Now abclib's struct foo is called struct abc_foo.
C++ is worse in this regard because class names have linkage.
This is why C++ needs namespaces: so you can put classes in them.
If two libraries in a C program make "typedef struct stack" it's not
as bad as two "class stack" in the same C++ program.
As far as external name clashes go, that can be solved by technologies
outside of C, such as symbol export controls on shared libraries.
That is to say, you can have external names in a shared library, referenced
among its modules, which are not exposed outside of the shared library. The
external API is often a lot smaller than the sum total of all API's contained
in the component, internal plus external.
Even a short prefix on names goes a long way. A random three-letter prefix
gives you 26**3 possible namespaces.
Higher level languages with bindings to C libraries can hide that cruft, and
that's pretty much what matters nowadays. Nobody cares about programming at
large in the C language with nice namespaces.
Ultimately, a namespace feature would just translate into some mangling
that the linker level.
What might be nice would be to treat underscores as virtual namespace
delimiters. If I want to have a bunch of symbols in a scope that all begin with
foo_ it would be nice to have:
prefix foo_ {
typedef int x; // this is really foo_x
struct stack { // this is really struct foo_stack
int x; // this is just x
/* ... */
} s; // this is really foo_s
}
// pull foo_bar, foo_xyzzy and foo_x into this scope
// under the short aliases bar, xyzzy and x.
prefix foo_ bar, xyzzy, x;
This is just a dumb text processing hack that doesn't pretend it's anything
more (unlike C++ namespaces which are a text processing hack which pretends to
be more).
In the preprocessor:
#prefix FOO_
#define X Y // actually defines FOO_X Y
#endfix
#addpfx FOO_ A B C // #define-s A B C to be aliases for FOO_A, FOO_B, FOO_C.
Here, if FOO_B is a function-like macro, then B becomes a function-like
macro also. Design choices: it can have a life of its own (enduring after
#undef FOO_B) or it could be linked to FOO_B such that it follows redefinitions
of FOO_B, and disappears when #undef FOO_B is performed).