预处理指令(十二)
十一、预定义宏
预定义宏(predefined macros)包括:强制宏(mandatory macros)、环境宏(environment macros)、条件特征宏(conditional feature macros)以及其它预定义宏(other predefined macros)。
实现不能预先定义宏__cplusplus,也不能在任何标准头文件中定义该宏。
1、强制宏
ISO/IEC 9899:2024标准定义的强制宏如下表所示:
| 宏名 | 描述 |
| __DATE__ | 宏值是预处理编译单元的编译日期,编译日期使用“Mmm dd yyyy”格式的字符字符串字面量,其中月份名与asctime函数生成的月份名相同。如果dd值小于10,dd首字符是空格符。如果编译日期不可用,应提供实现定义的有效日期。① |
| __FILE__ | 宏值是当前源文件名(文件名应为字符字符串字面量。)。② |
| __LINE__ | 宏值是当前源代码行在当前源文件中的行号(行号是整数常量)。② |
| __STDC__ | 宏值是整数常量1,用于标识符合ISO标准的实现。 |
| __STDC_EMBED_NOT_FOUND__ | 宏值是整数常量0,表示资源搜索失败或者实现不支持#embed指令指定的嵌入形参序列中的形参。 |
| __STDC_EMBED_FOUND__ | 宏值是整数常量1,表示资源搜索成功,并且实现支持#embed指令指定的嵌入形参序列中的所有形参,并且资源不为空。 |
| __STDC_EMBED_EMPTY__ | 宏值是整数常量2,表示资源搜索成功,并且实现支持#embed指令指定的嵌入形参序列中的所有形参,但资源为空。 |
| __STDC_HOSTED__ | 如果实现为托管实现,该宏值是整数常量1;否则该宏值是整数常量0。 |
| __STDC_UTF_16__ | 宏值是整数常量1,表示char16_t类型值使用UTF-16编码。 |
| __STDC_UTF_32__ | 宏值是整数常量1,表示char32_t类型值使用UTF-32编码。 |
| __STDC_VERSION__ | 宏值是整数常量202311L(ISO/IEC 9899:2024标准。)。③ |
| __TIME__ | 宏值是预处理编译单元的编译时间,编译时间使用“hh:mm:ss”格式的字符字符串字面量,与asctime函数生成的时间格式一致。如果编译时间不可用,应提供实现定义的有效时间。① |
① 编译时间不可用的根本原因是编译时编译器无法从一个可靠的、确定性的来源获取当前日历时间。这种情况下编译器不能直接崩溃或者给出无意义的结果,而必须提供一个合理的、由实现定义的时间值作为替补。
② 源文件名和行号可以使用#line指令修改。
③ 该宏值始终保持为long int类型的整数常量,并随着ISO新标准的发布而增加。
| 版本 | ISO标准 | 值 |
| 第五版 | ISO/IEC 9899:2024 | 202311L |
| 第四版 | ISO/IEC 9899:2018 | 201710L |
| 第三版 | ISO/IEC 9899:2011 | 201112L |
| 第二版 | ISO/IEC 9899:1999 | 199901L |
| 第一版修订1 | ISO/IEC 9899:1990/Amd 1:1995 | 199409L |
强制宏由实现定义。强制宏(__FILE__和__LINE__除外。)在整个编译单元中保持不变。强制宏不得作为#define和#undef预处理指令的对象。
#define __STDC__ //非法。 #undef __LINE__ //非法。
2、环境宏
ISO/IEC 9899:2024标准定义的环境宏如下表所示:
| 宏名 | 描述 |
| __STDC_ISO_10646__ | 宏值是yyyymmL格式的整型常量,例如:202012L。如果实现定义了该宏,Unicode必需集(Unicode required set)中的每个字符存储到wchar_t类型对象时,其值都与该字符的短标识符(short identifier)相同;例如:printf("%#X %lc\n", L'中', L'\u4E2D');输出0X4E2D 中。 Unicode必需集包括指定年份和月份之前ISO/IEC 10646标准及其所有修订和技术勘误中定义的所有字符。如果使用其它编码,则不应该定义该宏,并且实际使用编码由实现定义。 |
| __STDC_MB_MIGHT_NEQ_WC__ | 宏值是整型常量1,用于表示wchar_t编码中,基本字符集成员不要求与其作为整型字符常量单独使用时的值相等;例如:L'A'==(wchar_t)'A'值可能是1,也可能是0。 |
环境宏由实现有条件地定义,在整个编译单元中保持不变。环境宏不得作为#define和#undef预处理指令的对象。
3、条件特征宏
ISO/IEC 9899:2024标准定义的条件特征宏如下表所示:
| 宏名 | 描述 |
| __STDC_ANALYZABLE__ | 宏值是整数常量1,表示实现符合ISO/IEC 9899标准附录L(可分析性)的规范。 (注:ISO/IEC 9899标准附录L规定了可选行为,这些行为有助于提高C程序的可分析性。) |
| __STDC_IEC_60559_BFP__ | 宏值是整型常量202311L,旨在表明实现符合ISO/IEC 9899标准附录F(ISO/IEC 60559浮点算术)中关于二进制浮点算术的规范。 |
| __STDC_IEC_559__ | 宏值是整型常量1,旨在表明实现符合ISO/IEC 9899标准附录F(ISO/IEC 60559浮点算术)中关于二进制浮点算术的规范。 (注:根据ISO/IEC 9899:2024标准,使用此宏是一种过时做法。) |
| __STDC_IEC_60559_DFP__ | 宏值是整型常量202311L,旨在表明实现支持十进制浮点类型,并符合ISO/IEC 9899标准附录F(ISO/IEC 60559浮点算术)中关于十进制浮点算术的规范。 |
| __STDC_IEC_60559_COMPLEX__ | 宏值是整型常量202311L,旨在表明实现符合ISO/IEC 9899标准附录G(ISO/IEC 60559兼容复数算术)的规范。 |
| __STDC_IEC_60559_TYPES__ | 宏值是整型常量202311L,旨在表明实现符合ISO/IEC 9899标准附录H(ISO/IEC 60559交换和扩展类型)的规范。 |
| __STDC_IEC_559_COMPLEX__ | 宏值是整型常量1,旨在表明实现遵循ISO/IEC 9899标准附录G(ISO/IEC 60559兼容复数算术)的规范。 (注:根据ISO/IEC 9899:2024标准,使用此宏是一种过时做法。) |
| __STDC_LIB_EXT1__ | 宏值是整型常量202311L,旨在表明实现支持ISO/IEC 9899标准附录K(边界检查接口)中定义的扩展。 |
| __STDC_NO_ATOMICS__ | 宏值是整型常量1,旨在表明实现不支持原子类型(包括_Atomic类型限定符)以及<stdatomic.h>头文件。 |
| __STDC_NO_COMPLEX__ | 宏值是整型常量1,旨在表明实现不支持复数类型以及<complex.h>头文件。 |
| __STDC_NO_THREADS__ | 宏值是整型常量1,旨在表明实现不支持<threads.h>头文件。 |
| __STDC_NO_VLA__ | 宏值是整型常量1,旨在表明实现不支持具有自动存储期的变长数组;以变长数组类型声明的形参会被调整并定义为具有自动存储期限的指针类型对象;因此对此类声明的支持是强制性的。 |
对于宏__STDC_LIB_EXT1__、__STDC_IEC_60559_BFP__、__STDC_IEC_60559_DFP__、__STDC_IEC_60559_COMPLEX__和__STDC_IEC_60559_TYPES__,其值为202311L,目的是宏值始终保持为long int类型的整型常量,并随着ISO/IEC 9899标准版本的发布而增加。
如果实现定义了宏__STDC_NO_COMPLEX__,实现不得定义宏__STDC_IEC_60559_COMPLEX__和宏__STDC_IEC_559_COMPLEX__。
条件特征宏由实现有条件地定义,在整个编译单元中保持不变。条件特征宏不得作为#define和#undef预处理指令的对象。
4、其它预定义宏
其它预定义宏应以下划线加大写字母开头;或者以两个下划线开头;或者是以下标识符之一:alignas、alignof、bool、false、static_assert、thread_local、true。
主要参考资料:
3、en.cppreference.com : Binary resource inclusion
4、gnu.org : Binary Resource Inclusion
5、thephd.dev : Implementing #embed for C and C++
6、en.cppreference.com : Replacing text macros