Doc. no. | DxxxxR0 |
Date: | 2022-08-08 |
Project: | Programming Language C++ |
Audience: | LEWG, EWG, SG22 |
Reply to: | Alisdair Meredith <[email protected]> |
R0: Original
Original version of the paper for the 2022 August mailing.
C++23 introduces the notion of library modules that export the whole content of the C++ Standard Library, except for any parts that are defined as macros. This paper reviews the library macros that are therefore not exported, and looks for ways to export that same functionality without requiring the modules language feature to become aware of macros.
Modules, introduced in C++20, are the preferred way to export and import libraries in modern C++. They offer benefits to efficient translation of C++ source code, and isolation against unexpected use of macros. As such, they do not allow for exporting of macros, so libraries with macro interfaces are not supported, which is most typically (but not exclusively) an issue for libraries interoperating with C.
When a library interface does require use of macros, the next best alternative
is for consumers to import a header module. In this mode, the compiler tries
to parse a header as a module, but also allows macros to escape as-if it were
#include
-ed. Not all headers are suitable for use as header
modules, and in particular, while the standard C++ library headers are mandated
to be compatible, there is no such guarantee for the C standard library headers
nor for the C compatibility headers such as <cstddef>
.
Finally, where a header is not an importable header module, the user must fall
back on the traditional preprocessor #include
. The C++ library
requirements ensure that the same functionality can be both imported and
#include
-ed as long as there is no devious use of the preprocessor
to cause them to differ. Note that such abuse is highly irregular and unlikely
to be encountered in practice.
This paper observes that several parts of the C language are exposed as macros,
rather than straight language facilities, and so are not usable in a modern
C++ code base without resorting all the way back to the direct use of
#include
. It will explore some alternative designs that could
remove this limitation.
assert
offsetof
#include <cstddef> template <typename A, typename B> struct Test { int data; }; using TestInts = Test<int, int>;static_assert(offsetof( Test<int, int>, data) == 0); // errorstatic_assert(offsetof((Test<int, int>), data) == 0); // errorstatic_assert(offsetof( TestInts, data) == 0); // OK static_assert(offsetof( decltype(Test<int, int>{}), data) == 0); // OK
setjmp
va_arg
and friends
errno
ATOMIC_
scalar_LOCK_FREE
ATOMIC_FLAG_INIT
Most of these solutions proposed below suggest ways to make macros from the C
headers a built-in part of the C++ language, to account for the
non-importability of macros. This direction may cause some concern for C/C++
interoperability, and hence should be reviewed keenly by SG22. The basis for
suggesting these changes is that C has, for some time, defined macros
corresponding to C++ keywords where they are used in a similar way in the
grammar, such as the contents of the header iso646.h
, and the
boolean literals true
and false
. When those headers
are parsed as C++, there is a requirement that those macros are not defined.
Similarly, C++ is incompatible with C headers that use reserved words for
identifiers, relying on the macro header not being included. This paper
is now suggesting the reverse, where features started out as macros in the C
standard now become language features in the C++ standard and the corresponding
headers no longer supply those macros for future C++ standards.
Identifiers that are reserved keywords in C++, and macros in C:
alignas
alignof
and
and_eq
bitand
bitor
bool
compl
false
not
not_eq
or
or_eq
static_assert
true
xor
xor_eq
The simplest solution to importing features defined by macros is to import
header units that contain them. This was not possible with C++20 as there were
concerns about the implementability of header modules that depended on C
headers, even in the case of the <cstd*>
headers that are
specified in a way that does not require direct inclusion of the corresponding
<std*.h>
header, as they are often implemented in that way
in practice.
One non-general-purpose way to minimize the issue would be the extend the range
of predefined macros, to encompass more of the values that in principle are
exposing properties of the compiler itself, such as CHAR_BIT
. It
is not clear what benefit is derived by delegating this behavior to the library
today. The author suspects the original intent, back when C was originally
standardized, was to avoid breaking code that also defined or redefined these
macros for its own purpose. However, that usage not well defined in C++, per
[cpp.predefined] 15.11p4:
If any of the pre-defined macro names in this subclause, or the identifierdefined
, is the subject of a#define
or a#undef
preprocessing directive, the behavior is undefined. Any other ...16.4.5.3.3 Macro names [macro.names]
1 A translation unit that includes a standard library header shall not#define
or#undef
names declared in any standard library header.16.4.6.3 Restrictions on macro definitions [res.on.macro.definitions]
The names and global function signatures described in 16.4.2.2 are reserved to the implementation. All object-like macros defined by the C standard library and described in this Clause as expanding to integral constant expressions are also suitable for use in#if
preprocessing directives, unless explicitly stated otherwise.
The other reason hypothesized is that maybe a cross-compiler would consume system headers for the target environment at compilation-time, in order to understand the target environment. It is unclear that such an implementation would prosper, given the amount of target-environment specific information that must be embedding into a cross-compiler to efficiently generate and schedule code for the target environment, so this speculation is also discounted.
Hence, the author recommends the following macros are removed from the library headers (in C++) and predefined by the compiler, with the original headers noted for reference. Note that most of these macros are not of a form reserved to the implementation, which is why they are specifically part of the library. Predefining these macros would change the bargain in [cpp.predefined] 15.11p4 (emphasis added):
4 If any of the pre-defined macro names in this subclause, or the identifier defined, is the subject of a#define
or a#undef
preprocessing directive, the behavior is undefined. Any other predefined macro names shall begin with a leading underscore followed by an uppercase letter or a second underscore.
Header <stdalign.h> #define __alignas_is_defined 1 Header <stdbool.h> #define __bool_true_false_are_defined 1
These two feature macros are defined indicate that certain keywords, which would be defined as macros in those same headers by C, are not available to be defined as macros by the program. Given that is the case by default in C++ where these are true keywords, these feature macros exist purely for translating source shared between C and C++ compilers. They do follow the correct form for a reserved identifier, and should be predefined in C++ as the feature they are indicating support for is universally defined in C++, regardless of whether the corresponding C header has been included.
Note that predefining these macros also plays well with C++23 undeprecating the C standard library headers, so that these macros are no longer implicitly deprecated.
Header <climits> Header <limits.h> #define CHAR_BIT see below #define SCHAR_MIN see below #define SCHAR_MAX see below #define UCHAR_MAX see below #define CHAR_MIN see below #define CHAR_MAX see below #define MB_LEN_MAX see below #define SHRT_MIN see below #define SHRT_MAX see below #define USHRT_MAX see below #define INT_MIN see below #define INT_MAX see below #define UINT_MAX see below #define LONG_MIN see below #define LONG_MAX see below #define ULONG_MAX see below #define LLONG_MIN see below #define LLONG_MAX see below #define ULLONG_MAX see below Header <cstdint> Header <stdint.h> #define PTRDIFF_MIN see below #define PTRDIFF_MAX see below #define SIZE_MAX see below #define SIG_ATOMIC_MIN see below #define SIG_ATOMIC_MAX see below #define WCHAR_MIN see below #define WCHAR_MAX see below
Header <atomic> // importable Header <stdatomic.h> #define ATOMIC_BOOL_LOCK_FREE see below #define ATOMIC_CHAR_LOCK_FREE see below #define ATOMIC_CHAR8_T_LOCK_FREE see below #define ATOMIC_CHAR16_T_LOCK_FREE see below #define ATOMIC_CHAR32_T_LOCK_FREE see below #define ATOMIC_WCHAR_T_LOCK_FREE see below #define ATOMIC_SHORT_LOCK_FREE see below #define ATOMIC_INT_LOCK_FREE see below #define ATOMIC_LONG_LOCK_FREE see below #define ATOMIC_LLONG_LOCK_FREE see below #define ATOMIC_POINTER_LOCK_FREE see below
These are the remaining macros that would not be addressed by such a resolution, completing our audit of macros in the standard library interface:
Header <cstddef> Header <stddef.h> #define NULL see below #define offsetof(P, D) see below Header <cstdlib> Header <stdlib.h> #define NULL see below #define EXIT_FAILURE see below #define EXIT_SUCCESS see below #define RAND_MAX see below #define MB_CUR_MAX see below Header <cfloat> Header <float.h> #define FLT_ROUNDS see below #define FLT_EVAL_METHOD see below #define FLT_HAS_SUBNORM see below #define DBL_HAS_SUBNORM see below #define LDBL_HAS_SUBNORM see below #define FLT_RADIX see below #define FLT_MANT_DIG see below #define DBL_MANT_DIG see below #define LDBL_MANT_DIG see below #define FLT_DECIMAL_DIG see below #define DBL_DECIMAL_DIG see below #define LDBL_DECIMAL_DIG see below #define DECIMAL_DIG see below #define FLT_DIG see below #define DBL_DIG see below #define LDBL_DIG see below #define FLT_MIN_EXP see below #define DBL_MIN_EXP see below #define LDBL_MIN_EXP see below #define FLT_MIN_10_EXP see below #define DBL_MIN_10_EXP see below #define LDBL_MIN_10_EXP see below #define FLT_MAX_EXP see below #define DBL_MAX_EXP see below #define LDBL_MAX_EXP see below #define FLT_MAX_10_EXP see below #define DBL_MAX_10_EXP see below #define LDBL_MAX_10_EXP see below #define FLT_MAX see below #define DBL_MAX see below #define LDBL_MAX see below #define FLT_EPSILON see below #define DBL_EPSILON see below #define LDBL_EPSILON see below #define FLT_MIN see below #define DBL_MIN see below #define LDBL_MIN see below #define FLT_TRUE_MIN see below #define DBL_TRUE_MIN see below #define LDBL_TRUE_MIN see below Header <cfenv> Header <fenv.h> #define FE_ALL_EXCEPT see below #define FE_DIVBYZERO see below // optional #define FE_INEXACT see below // optional define FE_INVALID see below // optional #define FE_OVERFLOW see below // optional #define FE_UNDERFLOW see below // optional #define FE_DOWNWARD see below // optional #define FE_TONEAREST see below // optional #define FE_TOWARDZERO see below // optional #define FE_UPWARD see below // optional #define FE_DFL_ENV see below Header <cstdint> Header <stdint.h> #define INTN_MIN see below #define INTN_MAX see below #define UINTN_MAX see below #define INT_FASTN_MIN see below #define INT_FASTN_MAX see below #define UINT_FASTN_MAX see below #define INT_LEASTN_MIN see below #define INT_LEASTN_MAX see below #define UINT_LEASTN_MAX see below #define INTMAX_MIN see below #define INTMAX_MAX see below #define UINTMAX_MAX see below #define INTPTR_MIN see below #define INTPTR_MAX see below #define UINTPTR_MAX see below #define WINT_MIN see below #define WINT_MAX see below #define INTN_C(value) see below #define UINTN_C(value) see below #define INTMAX_C(value) see below #define UINTMAX_C(value) see below Header <cstdarg> Header <stdarg.h> #define va_arg(V, P) see below #define va_cpoy(VDST, VSRC) see below #define va_end(V) see below #define va_start(V, P) see below Header <csetjmp> Header <setjmp.h> #define setjmp(env) see below Header <csignal> Header <signal.h> #define SIG_DFL see below #define SIG_ERR see below #define SIG_IGN see below #define SIGABRT see below #define SIGFPE see below #define SIGILL see below #define SIGINT see below #define SIGSEGV see below #define SIGTERM see below Header <cstdio> Header <stdio.h> #define NULL see 17.2.3 #define _IOFBF see below #define _IOLBF see below #define _IONBF see below #define BUFSIZ see below #define EOF see below #define FOPEN_MAX see below #define FILENAME_MAX see below #define L_tmpnam see below #define SEEK_CUR see below #define SEEK_END see below #define SEEK_SET see below #define TMP_MAX see below #define stderr see below #define stdin see below #define stdout see below Header <cinttypes> Header <inttypes.h> #define PRIdN see below #define PRIiN see below #define PRIoN see below #define PRIuN see below #define PRIxN see below #define PRIXN see below #define SCNdN see below #define SCNiN see below #define SCNoN see below #define SCNuN see below #define SCNxN see below #define PRIdLEASTN see below #define PRIiLEASTN see below #define PRIoLEASTN see below #define PRIuLEASTN see below #define PRIxLEASTN see below #define PRIXLEASTN see below #define SCNdLEASTN see below #define SCNiLEASTN see below #define SCNoLEASTN see below #define SCNuLEASTN see below #define SCNxLEASTN see below #define PRIdFASTN see below #define PRIiFASTN see below #define PRIoFASTN see below #define PRIuFASTN see below #define PRIxFASTN see below #define PRIXFASTN see below #define SCNdFASTN see below #define SCNiFASTN see below #define SCNoFASTN see below #define SCNuFASTN see below #define SCNxFASTN see below #define PRIdMAX see below #define PRIiMAX see below #define PRIoMAX see below #define PRIuMAX see below #define PRIxMAX see below #define PRIXMAX see below #define SCNdMAX see below #define SCNiMAX see below #define SCNoMAX see below #define SCNuMAX see below #define SCNxMAX see below #define PRIdPTR see below #define PRIiPTR see below #define PRIoPTR see below #define PRIuPTR see below #define PRIxPTR see below #define PRIXPTR see below #define SCNdPTR see below #define SCNiPTR see below #define SCNoPTR see below #define SCNuPTR see below #define SCNxPTR see below Header <cmath> Header <math.h> #define HUGE_VAL see below #define HUGE_VALF see below #define HUGE_VALL see below #define INFINITY see below #define NAN see below #define FP_INFINITE see below #define FP_NAN see below #define FP_NORMAL see below #define FP_SUBNORMAL see below #define FP_ZERO see below #define FP_FAST_FMA see below #define FP_FAST_FMAF see below #define FP_FAST_FMAL see below #define FP_ILOGB0 see below #define FP_ILOGBNAN see below #define MATH_ERRNO see below #define MATH_ERREXCEPT see below #define math_errhandling see below Header <clocale> Header <locale.h> #define NULL see 17.2.3 #define LC_ALL see below #define LC_COLLATE see below #define LC_CTYPE see below #define LC_MONETARY see below #define LC_NUMERIC see below #define LC_TIME see below Header <ctime> Header <time.h> #define NULL see 17.2.3 #define CLOCKS_PER_SEC see below #define TIME_UTC see below Header <cerrno> Header <errno.h> #define errno see below #define E2BIG see below #define EACCES see below #define EADDRINUSE see below #define EADDRNOTAVAIL see below #define EAFNOSUPPORT see below #define EAGAIN see below #define EALREADY see below #define EBADF see below #define EBADMSG see below #define EBUSY see below #define ECANCELED see below #define ECHILD see below #define ECONNABORTED see below #define ECONNREFUSED see below #define ECONNRESET see below #define EDEADLK see below #define EDESTADDRREQ see below #define EDOM see below #define EEXIST see below #define EFAULT see beloww #define EFBIG see below #define EHOSTUNREACH see below #define EIDRM see below #define EILSEQ see below #define EINPROGRESS see below #define EINTR see below #define EINVAL see below #define EIO see below #define EISCONN see below #define EISDIR see below #define ELOOP see below #define EMFILE see below #define EMLINK see below #define EMSGSIZE see below #define ENAMETOOLONG see below #define ENETDOWN see below #define ENETRESET see below #define ENETUNREACH see below #define ENFILE see below #define ENOBUFS see below #define ENODATA see below #define ENODEV see below #define ENOENT see below #define ENOEXEC see below #define ENOLCK see below #define ENOLINK see below #define ENOMEM see below #define ENOMSG see below #define ENOPROTOOPT see below #define ENOSPC see below #define ENOSR see below #define ENOSTR see below #define ENOSYS see below #define ENOTCONN see below #define ENOTDIR see below #define ENOTEMPTY see below #define ENOTRECOVERABLE see below #define ENOTSOCK see below #define ENOTSUP see below #define ENOTTY see below #define ENXIO see below #define EOPNOTSUPP see below #define EOVERFLOW see below #define EOWNERDEAD see below #define EPERM see below #define EPIPE see below #define EPROTO see below #define EPROTONOSUPPORT see below #define EPROTOTYPE see below #define ERANGE see below #define EROFS see below #define ESPIPE see below #define ESRCH see below #define ETIME see below #define ETIMEDOUT see below #define ETXTBSY see below #define EWOULDBLOCK see below #define EXDEV see below Header <atomic> // importable #define ATOMIC_VAR_INIT(value) see below // deprecated Header <stdatomic.h> #define _Atomic(T) std-atomic<T> #define ATOMIC_FLAG_INIT see below
The vast majority of macros that are exported from library headers are literal
constants, mostly integer constants. It is highly desirable that these named
values be available through an imported library interface, if
import
is to be a complete solution for accessing library code.
In particular, the C++ library itself would need such a facility for the
<version>
header.
In the ideal world, a macro like:
#define __cpp_lib_addressof_constexpr 201603L // also in <memory>would be replaced by code like:
inline constexpr auto __cpp_lib_addressof_constexpr = 201603L;However, such a transformation would not work for code relying on testing the literal value through the preprocessor, which is a key motivating use case:
#if __cpp_lib_addressof_constexpr >= 201603L constexpr void my_func(); #else # error `my_func` requires the library function `addressof` be `constexpr`. #endif
Note that the main problem that module interfaces protect us from is unexpected
text substitution by macros, that act in violation of any scoping principles.
Our proposed solution is, however, to invent a new preprocessor directive,
#literal
. The intent is that literal
s are never
text substitutions, but evaluated each time a preprocessor directive needs a
value, such as #if SYMBOL > VALUE
or
defined(SYMBOL)
. Otherwise, literal
values are not
subject to macro replacement. After the final phase of preprocessing, all
literal
values are transformed to integral constants in the global
namespace, as if defined:
inline constexpr auto __cpp_lib_addressof_constexpr = 201603L;where the
constexpr
keyword would be better replaced by
consteval
if that were legal and meaningful. In particular, a
consteval
interpretation might allow multiple modules to export
the same literal
s, as long as the values are consistent.
A literal
may be multiply defined, as long as each evaluation
would produce the same value and type. A literal
may not be
undefined. The string produced by stringization and token-pasting a
literal
is unspecified, giving implementers a variety of freedoms
to render the value. For example, they may wish to select an integer suffix to
ensure the correct integral type is inferred, or merely rely on the integer
promotion rules when parsing an integer for the same effect; they might
optionally insert digit separators to help readers with large values; or maybe
they would follow exactly the form in the source when defined. We prefer to
leave the chosen rendering unspecified, rather than implementation defined, in
order to give implementers freedom to find their own best balance without
overburdening, users should not rely on a specific format, and certainly not
for portable code.
When interacting with legacy and 3rd party codebases, we might encounter an
attempt to #define
as a macro an identifier that has already been
defined as a literal
. To ease transition into the new world, we
recommending accepting such a #define
as a deprecated application
of literal
, not create the macro, and simply evaluate to ensure
that the values are the same. Similarly, we would deprecate attempts to
undefine
a literal
, rather than make them ill-formed,
for the initial specification of the feature.
A trickier question arises when trying to declare a literal
that
has already been defined as a macro. While it is tempting to treat it the same
as an attempt to #define
a literal
, and so promote
from a macro to a literal
, it is possible that text substitutions
have already occurred, that we do not want to track and reverse. This may be
an acceptable restriction. One alternative is to ignore the
literal
definition and retain the macro, but that would undermine
the intent of putting literals safely into the preprocessor. The third option
would be to make this a diagnosable error, noting that the implementation is
free to continue translation after issuing a diagnostic. This is superficially
similar to deprecation and the first option, although the diagnostic is
mandated, rather than optional for a deprecated facility, and the implementer
has more freedom to define their own semantics for how translation continues.
Second thought: stringization for token pasting may require rendering a documented form that is usable in an identifier to define a variable or another macro; that would disallow digit separators, and require documentation specifying the exact rules for integer suffices.
Note that this proposal covers only integer literals. There may be interest in pursuing string literals that support literal concatenation in a similar way, but that is deemed beyond the scope of the immediate need. Floating point literals are initially out of scope as the preprocessor itself cannot use them, and alternative techniques already present in the language can address such problems as arise. Similarly, null pointer constants and specifically the macro null are out of scope for now, as forcing a typed evaluation of the unspecified `0` literal would force an integer rather than null pointer representation, no longer fit for purpose.
assert
as a Language Feature
Any serious discussion of assert
belongs in SG21, Contract
Programming. However, it is worth sufficient discussion here to determine
whether this is a problem we want to see solved directly, and send that
feedback to SG21.
A proposal to satisfy the needs of enabling assert
in modern C++
code that does not rely on #include
is to make assert
an operator, claiming either a keyword or a contextual keyword, and explicitly
not define assert
as a macro in <cassert>
and
<assert.h>
.
In addition to resolving the macro import issue, this would further resolve
many issues surrounding macros not recognizing C++ matched brackets syntax
for brackets other than parens, such as <>
, {}
,
and []
, which are significantly more common in C++ than in C,
where the macro formulation seems reasonable.
Note that any attempt to turn assert
into an operator is going to
run into issues around build environments enabling and disabling its use,
interaction with users defining and undefining NDEBUG
in existing
code, and users relying on assert
expanding to nothing and so
containing non-compiling code in certain uses. It is likely that a C++ assert
operator would want to integrate with the configurable violation handling under
discussion in SG21, and so we would recommend moving any non-superficial
discussion into that study group.
offsetof
Operator
setjmp
va_arg
and friends
errno
Several other NB comments are filed around the clarity of defining macros with a bad name. For ease of catching any interactions, we propose to resolve them as part of this same paper.
The current prohibition against redefining keywords as macros is in a library clause about names reserved to the library, despite not relying on any library behavior. We recommend moving this paragraph up into the core clause, adjacent to the wording prohibiting redefining other identifiers as macros.
The prohibition on undefining or redefining predefined macros produces undefined behavior rather than an ill-formed program. This kind of undefined behavior in simply preprocessing the text of the source program is hard to justify, as the usage is very easy to diagnose. Hence, we recommend diagnosing an ill-formed program is the right behavior. Note that an implementation remains free to continue translation and accept the program, if that is its behavior today, as long as it diagnoses use of a non-conforming extension while doing so.
_Pragma
There is no prohibition against defining or undefining _Pragma
as
a macro, while there is such a prohibition for the token defined
.
Even though _Pragma
is an identifier reserved to the
implementation, we recommend extending the same prohibition, consistent with
the prohibition on undefining or redefining a predefined macro, as they all
have names that are also reserved to the implementation, yet we explicitly
state this property for them≥
Proposed changes to the working draft, including a drive-by fix moving the prohibition against defining keywords as macros from the library clauses into the core clause defining the preprocessor.
15.11 Predefined macro names [cpp.predefined]
- The following macro names shall be defined by the implementation:
__cplusplus
The integer literal202002L
.
[Note 1: Future revisions of C++ will replace the value of this macro with a greater value. —end note]
The names listed in [tab:cpp.predefined.ft].
The macros defined in [tab:cpp.predefined.ft] shall be defined to the corresponding integer literal. [Note 2: Future revisions of C++ might replace the values of these macros with greater values. —end note]
The names listed in [tab:cpp.predefined.cft].
The macros defined in [tab:cpp.predefined.cft] shall be defined to the corresponding integer literal.
__DATE__
The date of translation of the source file: a character string literal of the form"Mmm dd yyyy"
, ...
Table 2X: C feature-test macros [tab:cpp.predefined.cft] Macro name Value __alignas_is_defined
1 __alignof_is_defined
1 __bool_true_false_are_defined
1
IfA translation unit shall not#define
or#undef
names lexically identical to any of the pre-defined macro names in this subclause, or the identifierdefined
, or the identifier_Pragma
is the subject of a. Any other predefined macro names shall begin with a leading underscore followed by an uppercase letter or a second underscore.#define
or a#undef
preprocessing directive, the behavior is undefined
[Note N: The identifiers__has_include
,__has_cpp_attribute
,__VA_ARGS__
, and__VA_OPT__
may not be the subject of a#define
or a#undef
preprocessing directive due to the restrictions on where they may appear in code. —end note]- A translation unit shall not
#define
or#undef
names lexically identical to keywords, to the identifiers listed in Table 5, or to the attribute-tokens described in 9.12, except that the nameslikely
andunlikely
may be defined as function-like macros (15.6).16.4.5.3.3 Macro names [macro.names]
- A translation unit that includes a standard library header shall not
#define
or#undef
names declared in any standard library header.A translation unit shall not#define
or#undef
names lexically identical to keywords, to the identifiers listed in Table 5, or to the attribute-tokens described in 9.12, except that the nameslikely
andunlikely
may be defined as function-like macros (15.6).17.15.4 Header
<stdalign.h>
synopsis [stdalign.h.syn]#define __alignas_is_defined 1
The contents of the C++ header<stdalign.h>
are the same as the C standard library header<stdalign.h>
, with the following changes: The header<stdalign.h>
does not define a macro namedalignas
.
See also: ISO C 7.15
The C++ header<stdalign.h>
is empty.
[Note 1:alignas
andalignof
are keywords in C++ (5.11). —end note]17.15.5 Header
<stdbool.h>
synopsis [stdbool.h.syn]#define __bool_true_false_are_defined 1
The content`s of the C++ header<stdbool.h>
are the same as the C standard library header<stdbool.h>
, with the following changes: The header<stdbool.h>
does not define macros namedbool
,true
, orfalse
.
See also: ISO C 7.18
The C++ header<stdbool.h>
is empty.
[Note 1:bool
,true
, andfalse
are keywords in C++ (5.11). —end note]Acknowledgements
Thanks to Matt Godbolt for providing and hosting Compiler Explorer, which made testing the code samples on the necessary range of compilers so easy.
References
- N3801 Removing Undefined Behavior from the Preprocessor, Gabriel Dos Reis
- N4219 Fixing the specification of universal-character-names, David Krauss
- N4220 An update to the preprocessor specification, David Krauss
- N4858 Disposition of Comments for CD Ballot, ISO/IEC CD 14882, Barry Hedquist
- P1705R1 Enumerating Core Undefined Behavior, Shafik Yaghmour
- P2234R1 Consider a UB and IF-NDR Audit Scott Schurr