Doc. no. DxxxxR0
Date: 2022-08-08
Project: Programming Language C++
Audience: LEWG, EWG, SG22
Reply to: Alisdair Meredith <[email protected]>

Modules and Macros

Table of Contents

  1. Abstract
  2. Stating the problem
  3. Propose Solutions
  4. Other Suggestions
  5. Formal Wording
  6. Acknowledgements
  7. References

Revision History

R0: Original

Original version of the paper for the 2022 August mailing.

Abstract

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.

Stating the problem

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.

Literals

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);  // error
static_assert(offsetof((Test<int, int>), data) == 0);  // error
static_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

Proposed Solutions

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:

More Header Modules

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.

More Predefined Macros

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 identifier defined, 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.

Recommendations to predefine

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

Audit remaining macros

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

Exportable Literals

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 literals 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 literals, 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

Other Suggestions

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.

Improve Location of Wording on Redefining Keywords

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.

Ill-formed, Diagnostic Required

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.

Redefining _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≥

Integrated Proposed Wording

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]

  1. The following macro names shall be defined by the implementation:

    __cplusplus
        The integer literal 202002L.
        [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
  1. If A translation unit shall not #define or #undef names lexically identical to any of the pre-defined macro names in this subclause, or the identifier defined, or the identifier _Pragma 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.

    [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]
  2. 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 names likely and unlikely may be defined as function-like macros (15.6).

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.
  2. 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 names likely and unlikely may be defined as function-like macros (15.6).

17.15.4 Header <stdalign.h> synopsis [stdalign.h.syn]

#define __alignas_is_defined 1
  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 named alignas.

    See also: ISO C 7.15

    The C++ header <stdalign.h> is empty.

    [Note 1: alignas and alignof 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
  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 named bool, true, or false.

    See also: ISO C 7.18

    The C++ header <stdbool.h> is empty.
    [Note 1: bool, true, and false 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