Whenever I try to use a C++ library, no matter how simple the API is it’s just a pain to get it working with any other language. There are a couple of examples I can think of (Dear ImGui, Tracy, vst3sdk…).
If a programmer wants to use a C++ library from another language, they’ll have to link with the library seperately and use a C API header file (see cimgui, tracy). Making bindings will require interfacing with libc++/libstdc++ too (see odin-imgui).

It may go around the other way, so trying to use a C library in a C++ project doesn’t work because the library doesn’t cast pointers!
The stb libraries are a perfect example of libraries that work everywhere, seriously go try all the compilers (msvc, gcc, clang, tcc…), standards (from C95 to C23) and OSes. You can compile and link them however you want and it’s extremely easy to do so.
We need more C libraries that are:
- Compatible with all the C standards (from C95 to C23, preferrably C89 support too).
- Compatible with C++ (will make this into a seperate blog post).
- Works with most compilers (preferably don’t rely on compiler extensions except for things like thread local).
This is also one of the advantages of using standard C89/C99, you’re (mostly) compatible with all other C standards, and the library doesn’t rely on implicit primitive/pointer casts and has a macro for both C and C++ initializers, now you’re library is compatible with C++ too! (there may be other details I’m missing, but those are for another blog post).
Now here is another thing: if I want to write a really portable C library, what C standard should it use? It depends: If the library is expected to run in embedded environments, then C89 is the obvious choice, but other than that C99 is more than fine portability-wise.
That raises the question: what’s the difference between using C89 and C99 anyway? All that comes to mind when thinking of C99 is inlining (compilers do that anyway), VLAs (optional in C11, therefore bad for portability), one line comments (not that big of a deal), designated initializers (which are quite nice when writing, say, Vulkan structs but also not a big deal) and compound literals (not a big deal since C89 allows inserting scopes inside functions). C99 is just for comfort… But it’s OK since C99 is pretty portable, unless you’re really that portable and want to support all sorts of C compilers (Plan9’s C compiler perhaps?).
Conclusion:
If writing a library, write standard C89/C99 that is compatible with C++, doesn’t use compiler extensions (unless it’s really needed), and works with most compilers (bonus points if it works with tcc or cproc).