I haven't written actual C code in decades. Did C11 get magic statics with thread-safe initialization like C++11? Does C even have non-trivial initialization of statics local variables?
I don't know why it would be magic to have thread-local storage. Thread-local variables are either static or extern. Thread-local static variables are initialized like normal static variables (initialization on declaration line occurs on first instantiation), but with a separate copy per thread.
N1570, sec. 6.2.4, para. 4: An object whose identifier is declared with the storage-class specifier _Thread_local has thread storage duration. Its lifetime is the entire execution of the thread for which it is created, and its stored value is initialized when the thread is started. There is a distinct object per thread, and use of the declared name in an expression refers to the object associated with the thread evaluating the expression.
N1570, sec. 6.7.9, para. 10: If an object that has static or thread storage duration is not initialized explicitly, then [it is initialized to NULL or 0 as appropriate, including all-bits-zero padding in structs]
Not thread local storage. Plain function statics are initialized on first use in c++ (if the initializer is not trivial), and this initialization is thread safe. There is a simple algorithm to implement it that has very little overhead on the already initialized case that is known as magic statics (it is basically an instance of the double checked locking pattern).
C does have initialization of local variables, including static.
It does not have any thread safety in standard for these, however, so no thread safe singletons. (You can get them initialized by linker or runtime safely, of course, e.g. ELF .bss and UCRT on Windows)
You can use atomics to implement such a singleton if they are available.
This is one of the main reasons why C is more portable than C++.