Modules either have types as part of their interface, or haven't. I C, the declarations shipped in the interface header represent the interface, and the types declared in it are public types.
C also supports symbols with internal linkage.
What exactly is missing?
> module initialization/shutdown,
What's wrong with initializing objects? Languages such as Rust also rely on factory methods to instantiate objects.
> linking with type checking,
The interface headers define the symbols, which must correspond to the symbols handled by the linker. What's missing?
> namespaces.
That definitely C doesn't support as a first class citizen, but this is nothing that symbol prefixes don't handle.
It lacks almost everything that a programming language with modules offers on its type system, and compiler toolchain.
Proper public/private types, module initialization/shutdown, linking with type checking, namespaces.
One can fake modules with void pointers, static types on translation units, prefixes that hopefully no one else is using, and that is about it.