C99 has some very hard-to-replicate features; most notably designated initializers. Without them, you cannot statically initialize any union member except the first. This is a significant problem for me.
C99 is mostly supported by every C compiler I am aware of except MSVC, so it would be portable if not for Microsoft.
> Even if you don't really use any language features unique to C++, you would still get some safer library functions and better portability than you would if you limited yourself to the C99 standard.
C++ is not available in the Linux kernel, it mangles names, and it's tricky to be disciplined enough to write in a C++ subset without letting C++ features creep in, especially on a multi-person project. Once you let C++ features creep in you can inadvertently end up with runtime static initializers, type_info symbols, exception unwinding code and debugging symbols, etc.
My current compromise is to compile as C99 everywhere except on MSVC, where I will compile as C++ and use C++ alternatives to features like designated initializers.
long long foo; /* bigger ints on 32-bit platforms */
uint32_t bar; /* stdint.h, integers of specific bit width */
int array[n]; /* length-n array, where n is a variable */
for (int i = 0; i < n; i++) /* loop-local variable */
Also, the safer stdio functions like snprintf. - declarations mixed with statements
- declarations in `for` constructs
- hexadecimal floating-point literals and conversion specifiers
- the strtoxx( ) conversion routines
- the restrict qualifier
- the expanded math library
- designated initializers
- extended integer types
- compound literals
- // comments
- VLAs
- complex support
Note that some of these features are still not present in C++11.C11 features that I have used in the past few months:
- CMPLX macros
- anonymous structures and unions
- <stdalign.h> struct { struct y y; bool flag; } = { .flag = true };In general, C feels well-suited to be the language that (almost) every other language can talk to; C++ just doesn't fit that role so well.
I'm not sure how else you think C++ could handle its goals without the name mangling: overloading and compatibility with C's linker system. If you have two overloaded "foo" functions you need to somehow designated them as separate linker symbols.
C has similar problems of its own: like what's the calling convention for the exported symbol? Do I push the arguments on the stack, and who cleans up? Do some arguments go into registered? Where does the return value go? What's the layout of a struct? All things are platform, compiler and compiler configuration dependent.
What other languages, that compile to object files or shared objects, that support the level of OO features etc. that C++ has, have a well-defined ABI?
Plus, sometimes having fewer features is itself a feature. I would say that this is especially true when comparing the slim, minimal design of C with the "everything and the kitchen sink" approach of C++. Not that C++ is never useful in its own right, but that doesn't mean its appropriateness for a given task is always greater than or equal to that of C.
This mostly means it's incompatible with C even in the parts of the language both of them share. Completely valid and idiomatic C code will therefore not always compile if you use a C++ compiler.