Define C23 header version macros

Joseph Myers josmyers@redhat.com
Fri Nov 21 22:02:40 GMT 2025


On Thu, 20 Nov 2025, Paul Eggert wrote:

> > --- a/assert/assert.h
> > +++ b/assert/assert.h
> > @@ -34,6 +34,12 @@
> >   #define	_ASSERT_H	1
> >   #include <features.h>
> >   +#if __GLIBC_USE (ISOC23)
> > +# ifndef __STDC_VERSION_ASSERT_H__
> > +#  define __STDC_VERSION_ASSERT_H__ 202311L
> > +# endif
> > +#endif
> 
> assert.h is special because it can be multiply included with different effects
> each time. So shouldn't this be done like other assert macros? That is, define
> __STDC_VERSION_ASSERT_H__ without using the ifndef here, and near the file's
> start if _ASSERT_H is already defined then #undef __STDC_VERSION_ASSERT_H__
> there. Although this sort of thing matters only if the user fiddles with
> _ISOC23_SOURCE (which the user shouldn't do of course) it would be a bit more
> robust in that fiddly situation.

I don't think there can be any reasonable expectations for how 
__STDC_VERSION_ASSERT_H__ is or isn't defined if the header is included 
more than once with different standard versions.  features.h *does* have 
multiple include guards (and bits/libc-header-start.h is only for C 
standard feature test macros), so fiddling with _ISOC23_SOURCE after 
including a header wouldn't even do anything useful.

> Also, suppose the user compiles with --std=gnu2y? What should the value of
> __STDC_VERSION_ASSERT_H__ be then? Perhaps it should be some intermediate
> value like 202505L for the latest C2y draft that glibc supports? Similarly for
> other __STDC_VERSION_*_H__ macros.

At the February 2023 WG14 meeting, there was a discussion of whether 
__has_c_attribute values should change in future standard versions if 
there are no changes to a particular attribute, and the opinion poll 
expressed the view that such values should not change in that case.  That 
doesn't say what would happen for __STDC_VERSION_*_H__ but does tend to 
suggest not changing the values in the absence of changes to a header 
(which is consistent with how the working draft has been edited so far for 
C2y), so that those macros are handled consistently with 
__has_c_attribute.  (It was agreed for __has_c_attribute to make the value 
reflect the __STDC_VERSION__ value for the final published standard, even 
when lower values were first put in working drafts as placeholders before 
the final __STDC_VERSION__ value for that version of the standard was 
known.)

If a particular header has changes in C2y *and* we've implemented all of 
them, we could choose to change the value like that.  It would need to be 
conditional on __GLIBC_USE (ISOC2Y), since each standard version says what 
the value of the macros is - *not* that they might have a higher value as 
well.

It's not always clear what's enough of a change to be worth updating the 
value of such a macro (or defining it for the first time); consider e.g. 
the version macro in <setjmp.h>, where it's questionable if there were 
really feature changes meriting defining a version macro (but CD1 comment 
GB-188 on that subject received no consensus in the vote at the February 
2023 meeting; the actual change to <setjmp.h> in C23 was to declare 
longjmp with [[noreturn]] instead of _Noreturn in the prototype given in 
the function description in the standard).

> > +# ifndef __STDC_VERSION_LIMITS_H__
> > +#  define __STDC_VERSION_LIMITS_H__ 202311L
> > +# endif
> 
> Why is the ifndef needed here, instead of a plain #define? Other places don't
> have such an ifndef (except for assert.h, which is special because it can be
> multiply included and which I discussed above).

(a) <limits.h> can get included together with GCC's <limits.h>, which 
might or might not define the macro depending on the GCC version (macro 
definition introduced in GCC 13), and (b) GCC diagnoses duplicate 
definitions of __STDC_* macros, even with the same value, which is why we 
need to take steps to avoid such duplicates in cases where some kind of 
multiple inclusion is possible.

> > +#if __GLIBC_USE (ISOC23)
> > +# define __STDC_VERSION_STDIO_H__ 202311L
> > +#endif
> 
> Since glibc supports C23 <stdio.h>'s features regardless of whether
> __GLIBC_USE (ISOC23) is true, how about doing this #define unconditionally?

Whether scanf functions handle 0b and 0B as binary for %i depends on 
__GLIBC_USE (ISOC23).

> Similarly for other __STDC_VERSION_*_H__ macros: the idea is to define each
> such macro if the corresponding C23 features are supported, regardless of
> whether __GLIBC_USE (ISOC23) is true.

Technically that would be valid in cases where no new declarations or 
macro definitions or semantics conditional on the language version are 
involved.  But given that if standard version X defines a value for the 
macro and standard version Y defines a new value, we can't use standard 
Y's value when compiling for standard X, doing something different just 
for the case where the standard imposes no constraints on the presence or 
value of such a macro (i.e. for standard versions before the macro was 
introduced for that header) doesn't seem that useful.

-- 
Joseph S. Myers
josmyers@redhat.com



More information about the Libc-alpha mailing list