The C++ standard allows an implementation to define macros like
__STDC_VERSION__, etc: __STDC__ and Clang does this for some of the macros, as does GCC.
However, this is a Very Bad Idea™ for many reasons and just because we can/have doesn’t mean we should. Users, rather reasonably, expect
__STDC__ to identify when they’re using a conforming C implementation because that’s how the macro is defined by the C standard in 6.10.8. You can see plenty of evidence for this
and it leads to surprising behaviors (code pulled from an example above):
(The GCC behavior probably surprises folks, it did for me; the Clang behavior is because we don’t define
__has_c_attribute in C++ mode.)
However, C++ is not conforming C plus some extra stuff; it’s core language specification is completely separate from the language specification for C, and there are tons of deviations between the languages. I think it’s dangerous to give the perception that C++ is conforming C code, and I think that our defining these macros makes it significantly harder to clearly identify whether Clang is compiling in C mode or C++ mode. Users have to know about this somewhat hidden gotcha and write
#ifndef __cplusplus and hope that’s sufficient in order to identify that they’re in C mode, but even that isn’t bulletproof because header files are sometimes shared between tools where the language mode may sometimes be something other than C++ but it still has a sufficiently compatible preprocessor (such as FORTRAN).
GCC also documents that this behavior is not ideal, and the conditions under which they define
__STDC__ do not match how we handle it in Clang (which is unconditionally defining it outside of Microsoft compatibility mode). Standard Predefined Macros (The C Preprocessor)
I propose that we stop pretending we’re a C compiler in C++ mode, and no longer predefine the following C-based macros which we currently define today:
That said, it’s unclear to me whether this would break code in practice, and if so, how much code. It’s tricky to measure this given the myriad of creative preprocessor macros appearing in header files. I think that the only two macros which are mildly defensible to keep are the UTF macros, due to C++11 and C++14 only defining them if
<cuchar> is included – however, they’re no longer mentioned in C++17 or later anywhere in the C++ standard, so I’d also be fine if we only defined those in C++11 and C++14 mode.
It’s worth noting that we can’t get rid of
__STDC_HOSTED__ because the C++ standard made that a mandatory macro: __STDC_HOSTED__, and Clang has never defined
__STDC_VERSION__. You could argue that users can identify C mode by the definition of
__STDC_VERSION__, and I’d argue that’s still user-hostile because the definition of
__STDC__ is that it’s a conforming C implementation, which C++ is not.