5.2.5 环境限度
NOTE
这一节很容易被忽略,但它非常重要:标准不是只讲语义,也规定了实现至少要支持到什么规模。这里列出的,是符合标准的实现必须保证支持的最小下限。
5.2.5.1 一般规定
- 翻译环境和执行环境都会约束语言翻译器和库的实现。下面总结的是符合标准的实现必须满足的、与语言有关的环境限度;与库有关的限度见第 7 章。
5.2.5.2 翻译限度
- 实现应能够翻译并执行一个程序,只要它使用了以下构造和实体,但没有超过下列限制:13)
- 块嵌套层数:
127 - 条件包含嵌套层数:
63 - 在一个声明中,对某个算术类型、结构体类型、联合体类型或
void类型施加修改的指针、数组和函数声明符总层数(任意组合):12 - 一个完整声明符中,带括号声明符的嵌套层数:
63 - 一个完整表达式中,带括号表达式的嵌套层数:
63 - 内部标识符或宏名中有意义的初始字符数:
63 - 外部标识符中有意义的初始字符数:
31 - 一个翻译单元中的外部标识符数:
4095 - 一个块中声明的块作用域标识符数:
511 - 一个预处理翻译单元中同时定义的宏标识符数:
4095 - 一个函数定义中的形参数:
127 - 一个函数调用中的实参数:
127 - 一个宏定义中的形参数:
127 - 一个宏调用中的实参数:
127 - 一条逻辑源代码行中的字符数:
4095 - 一个字符串字面量中的字符数(拼接之后):
4095 - 一个对象中的字节数(仅宿主环境):
32767 #include文件嵌套层数:15- 一个
switch语句中的case标号数(不含嵌套switch的case):1023 - 一个结构体或联合体中的成员数:
1023 - 一个枚举中的枚举常量数:
1023 - 单个成员声明列表中,结构体或联合体定义的嵌套层数:
63
- 块嵌套层数:
注
13)鼓励实现在可能时避免施加固定的翻译限度。
5.2.5.3 数值限度
5.2.5.3.1 一般规定
- 实现必须把本小节规定的全部限度写入文档。这些限度在头
<limits.h>与<float.h>中给出;此外,<stdint.h>中还规定了附加限度。
前向引用:整数类型 <stdint.h>(7.22)。
5.2.5.3.2 整数类型的特征 <limits.h>
- 下列值应替换为适合在条件包含预处理指令中使用的常量表达式;这些实现定义值应大于或等于所示值:
| 含义 | 宏 | 最小值 |
|---|---|---|
bool 类型对象的宽度 | BOOL_WIDTH | 1 |
| 最小非位字段对象(字节)的位数 | CHAR_BIT | 8 |
unsigned short int 的宽度 | USHRT_WIDTH | 16 |
unsigned int 的宽度 | UINT_WIDTH | 16 |
unsigned long int 的宽度 | ULONG_WIDTH | 32 |
unsigned long long int 的宽度 | ULLONG_WIDTH | 64 |
| 位精确整数类型支持的最大宽度 | BITINT_MAXWIDTH | >= ULLONG_WIDTH |
| 任意受支持区域设置下,多字节字符的最大字节数 | MB_LEN_MAX | 1 |
表示
char、signed char和unsigned char宽度的宏CHAR_WIDTH、SCHAR_WIDTH和UCHAR_WIDTH,都应展开为与CHAR_BIT相同的值。宏
SHRT_WIDTH应表示short int的宽度,并且应与USHRT_WIDTH相同;宏INT_WIDTH应表示int的宽度,并且应与UINT_WIDTH相同;宏LONG_WIDTH应表示long int的宽度,并且应与ULONG_WIDTH相同;宏LLONG_WIDTH应表示long long int的宽度,并且应与ULLONG_WIDTH相同。对于所有无符号整数类型,只要
<limits.h>或<stdint.h>为其定义了后缀为_WIDTH的宏并把宽度记作N,就还存在一个后缀为_MAX的宏,用来保存该类型可表示的最大值2^N - 1;该宏的类型,与“一个该类型对象经过整数提升后所得表达式”的类型相同。如果该值处于uintmax_t(7.22.1.5)的取值范围内,则该宏适合用于条件包含预处理指令。对于所有有符号整数类型,只要
<limits.h>或<stdint.h>为其定义了后缀为_WIDTH的宏并把宽度记作N,就还存在后缀为_MIN和_MAX的宏,用来保存该类型可表示的最小值-2^(N-1)与最大值2^(N-1)-1;这些宏的类型,与“一个该类型对象经过整数提升后所得表达式”的类型相同。如果这些值处于intmax_t(7.22.1.5)的取值范围内,则这些宏适合用于条件包含预处理指令。如果
char类型对象能够保存负值,则CHAR_MIN的值应与SCHAR_MIN相同,CHAR_MAX的值应与SCHAR_MAX相同。否则,CHAR_MIN的值应为0,而CHAR_MAX的值应与UCHAR_MAX相同(见 6.2.5)。
5.2.5.3.2 宏表展开
| 含义 | 宏 | 说明 |
|---|---|---|
bool 类型对象的宽度 | BOOL_WIDTH | 精确值为 1 |
| 最小非位字段对象的位数 | CHAR_BIT | 最小值为 8 |
char 的宽度 | CHAR_WIDTH | 与 CHAR_BIT 相同 |
signed char 的宽度 | SCHAR_WIDTH | 与 CHAR_BIT 相同 |
unsigned char 的宽度 | UCHAR_WIDTH | 与 CHAR_BIT 相同 |
unsigned short int 的宽度 | USHRT_WIDTH | 最小值为 16 |
short int 的宽度 | SHRT_WIDTH | 与 USHRT_WIDTH 相同 |
unsigned int 的宽度 | UINT_WIDTH | 最小值为 16 |
int 的宽度 | INT_WIDTH | 与 UINT_WIDTH 相同 |
unsigned long int 的宽度 | ULONG_WIDTH | 最小值为 32 |
long int 的宽度 | LONG_WIDTH | 与 ULONG_WIDTH 相同 |
unsigned long long int 的宽度 | ULLONG_WIDTH | 最小值为 64 |
long long int 的宽度 | LLONG_WIDTH | 与 ULLONG_WIDTH 相同 |
| 位精确整数类型支持的最大宽度 | BITINT_MAXWIDTH | 应大于或等于 ULLONG_WIDTH |
| 任意受支持区域设置下,多字节字符的最大字节数 | MB_LEN_MAX | 最小值为 1 |
此外,标准还要求:对于所有已经定义了 _WIDTH 宏的有符号/无符号整数类型,还应存在与之配套的 _MIN、_MAX 宏,其值和类型满足原文规定。
前向引用:类型的表示(6.2.6)、条件包含(6.10.2)、整数类型 <stdint.h>(7.22)。
5.2.5.3.3 浮点类型的特征 <float.h>
浮点类型的特征,是通过一个描述浮点数表示并允许其他值存在的模型来定义的。这些特征提供了实现的浮点运算信息。16)如果实现定义了
__STDC_IEC_60559_BFP__或__STDC_IEC_559__,则其浮点类型和浮点运算应符合本文档附录 F 所规定的 ISO/IEC 60559 要求。如果实现定义了__STDC_IEC_60559_COMPLEX__或__STDC_IEC_559_COMPLEX__,则其复数类型和复数运算应符合本文档附录 G 所规定的 ISO/IEC 60559 要求。对于每种浮点类型,模型使用以下参数:
s 符号(±1)
b 指数表示的底数(大于 1 的整数)
e 指数(介于最小值 emin 和最大值 emax 之间的整数)
p 精度(尾数中以 b 为底的位数)
fk 小于 b 的非负整数(尾数各位)2
3
4
5
- 对每种浮点类型,参数
b、p、emin、emax都是固定常量;对应浮点数x的模型为:
在该模型中:
- 若
f_1 > 0,则x称为规范化浮点数; - 若
x \ne 0、f_1 = 0且e = emin,则x称为次正规浮点数; - 若
x \ne 0、f_1 = 0且e > emin,则x称为非规范化浮点数; - 若全部
f_k = 0,则x是 0。
- 若
浮点类型必须能够表示有符号零或无符号零,以及全部规范化浮点数。除此之外,浮点类型还可以表示其他类型的浮点数,例如次正规数、非规范化数,以及非浮点数值,例如 NaN 和无穷大。
NaN表示 “Not-a-Number”。静默 NaN 在几乎所有算术运算中会传播而不引发浮点异常;信号 NaN 一般在作为算术操作数时引发浮点异常。所有
<float.h>中的整数值(除FLT_ROUNDS外)都应是适合用于条件包含预处理指令的常量表达式;所有浮点值都应是算术常量表达式。标准浮点类型加法的舍入模式由
FLT_ROUNDS的实现定义值表征:
FLT_ROUNDS | 含义 |
|---|---|
-1 | 无法确定 |
0 | 向零舍入 |
1 | 舍入到最近值,遇到中点时取偶 |
2 | 向正无穷舍入 |
3 | 向负无穷舍入 |
4 | 舍入到最近值,遇到中点时远离零 |
其他值表示实现定义的舍入行为。
- 浮点表达式和浮点常量可以在范围和精度都高于其类型要求的格式中求值,这种格式称为求值格式。赋值运算符和强制转换运算符的结果,则总是以其目标类型的格式给出。
FLT_EVAL_METHOD用于表征求值格式的使用范围:
FLT_EVAL_METHOD | 含义 |
|---|---|
-1 | 无法确定 |
0 | 按类型本身的范围和精度求值 |
1 | float 与 double 按 double 精度求值,long double 按自身精度求值 |
2 | 所有浮点运算与常量都按 long double 精度求值 |
其他负值表示实现定义行为。
次正规数是否存在,由
FLT_HAS_SUBNORM、DBL_HAS_SUBNORM、LDBL_HAS_SUBNORM的实现定义值表征:-1表示无法确定,0表示不存在,1表示存在。使用这些宏是一个将被淘汰的特性。若相应类型支持信号 NaN,则以下宏会被定义,并展开为该类型的信号 NaN 常量表达式:
FLT_SNAN
DBL_SNAN
LDBL_SNAN2
3
宏
INFINITY仅在实现为float支持无穷大时定义;它展开为表示正无穷或无符号无穷的float常量表达式。宏NAN仅在实现为float支持静默 NaN 时定义;它展开为表示静默 NaN 的float常量表达式。标准随后还给出了大量实现定义宏的下界要求,例如
FLT_RADIX、FLT_MIN_EXP、FLT_MAX_EXP、FLT_MAX、FLT_EPSILON、FLT_MIN、FLT_TRUE_MIN,以及对应的DBL_*、LDBL_*宏。它们分别约束:
- 指数表示的底数;
- 最小/最大指数;
- 可表示的最大有限值;
- 机器精度;
- 最小规范化正数;
- 最小正浮点数。
标准还给出了推荐实践和示例,展示一个满足最小要求的人工浮点表示,以及符合 ISO/IEC 60559 的
binary32/binary64形式下<float.h>宏可取的典型值。若实现支持十进制浮点类型,则
<float.h>中还会给出_Decimal32、_Decimal64、_Decimal128相关宏,例如:
DEC32_MANT_DIG
DEC64_MANT_DIG
DEC128_MANT_DIG
DEC32_MIN_EXP
DEC64_MIN_EXP
DEC128_MIN_EXP
DEC32_MAX_EXP
DEC64_MAX_EXP
DEC128_MAX_EXP
DEC32_MAX
DEC64_MAX
DEC128_MAX
DEC32_EPSILON
DEC64_EPSILON
DEC128_EPSILON
DEC32_MIN
DEC64_MIN
DEC128_MIN
DEC32_TRUE_MIN
DEC64_TRUE_MIN
DEC128_TRUE_MIN2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这些宏用于描述十进制浮点类型的系数位数、最小/最大指数、最大值、机器精度和最小正数等特征。
5.2.5.3.3 宏表展开
基础特征与求值方式
| 含义 | 宏 | 标准给出的下界/取值规则 |
|---|---|---|
| 舍入模式 | FLT_ROUNDS | -1/0/1/2/3/4 及其他实现定义值 |
| 求值格式 | FLT_EVAL_METHOD | -1/0/1/2 及其他负的实现定义值 |
| 是否具有 ISO/IEC 60559 的精度与指数范围 | FLT_IS_IEC_60559 DBL_IS_IEC_60559 LDBL_IS_IEC_60559 | 0 或 1 |
| 是否支持次正规数 | FLT_HAS_SUBNORM DBL_HAS_SUBNORM LDBL_HAS_SUBNORM | -1/0/1 |
| 信号 NaN | FLT_SNAN DBL_SNAN LDBL_SNAN | 仅在该类型支持信号 NaN 时定义 |
| 无穷大 | INFINITY | 仅在 float 支持无穷大时定义 |
| 静默 NaN | NAN | 仅在 float 支持 quiet NaN 时定义 |
指数底、尾数位、十进制位数
| 含义 | 宏 | 标准给出的最小值/规则 |
|---|---|---|
指数表示的底数 b | FLT_RADIX | 2 |
尾数位数 p | FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG | 实现定义,下界由原文公式约束 |
| 十进制往返无损位数 | FLT_DECIMAL_DIG DBL_DECIMAL_DIG LDBL_DECIMAL_DIG | 最小值分别为 6/10/10 |
| 最宽浮点类型的十进制往返无损位数 | DECIMAL_DIG | 最小值为 10 |
| 十进制有效数字位数 | FLT_DIG DBL_DIG LDBL_DIG | 最小值分别为 6/10/10 |
指数范围
| 含义 | 宏 | 标准给出的最小值/规则 |
|---|---|---|
最小指数 emin | FLT_MIN_EXP DBL_MIN_EXP LDBL_MIN_EXP | 实现定义,下界由原文公式约束 |
| 以 10 为底的最小指数 | FLT_MIN_10_EXP DBL_MIN_10_EXP LDBL_MIN_10_EXP | 最小值为 -37/-37/-37 |
最大指数 emax | FLT_MAX_EXP DBL_MAX_EXP LDBL_MAX_EXP | 实现定义,下界由原文公式约束 |
| 以 10 为底的最大指数 | FLT_MAX_10_EXP DBL_MAX_10_EXP LDBL_MAX_10_EXP | 最小值为 +37/+37/+37 |
数值范围与精度
| 含义 | 宏 | 标准给出的约束 |
|---|---|---|
| 最大可表示有限值 | FLT_MAX DBL_MAX LDBL_MAX | 实现定义,且绝对值应大于或等于示例值 |
| 最大规范化浮点数 | FLT_NORM_MAX DBL_NORM_MAX LDBL_NORM_MAX | 实现定义,且应大于或等于示例值 |
| 机器精度 | FLT_EPSILON DBL_EPSILON LDBL_EPSILON | 实现定义正值,且应小于或等于示例值 |
| 最小规范化正浮点数 | FLT_MIN DBL_MIN LDBL_MIN | 实现定义正值,且应小于或等于示例值 |
| 最小正浮点数 | FLT_TRUE_MIN DBL_TRUE_MIN LDBL_TRUE_MIN | 实现定义正值,且应小于或等于示例值 |
十进制浮点类型相关宏
| 含义 | 宏 |
|---|---|
| 十进制求值格式 | DEC_EVAL_METHOD |
| 十进制信号 NaN | DEC32_SNAN DEC64_SNAN DEC128_SNAN |
| 十进制正无穷 | DEC_INFINITY |
| 十进制静默 NaN | DEC_NAN |
| 系数位数 | DEC32_MANT_DIG DEC64_MANT_DIG DEC128_MANT_DIG |
| 最小指数 | DEC32_MIN_EXP DEC64_MIN_EXP DEC128_MIN_EXP |
| 最大指数 | DEC32_MAX_EXP DEC64_MAX_EXP DEC128_MAX_EXP |
| 最大有限值 | DEC32_MAX DEC64_MAX DEC128_MAX |
| 机器精度 | DEC32_EPSILON DEC64_EPSILON DEC128_EPSILON |
| 最小规范化正数 | DEC32_MIN DEC64_MIN DEC128_MIN |
| 最小次正规正数 | DEC32_TRUE_MIN DEC64_TRUE_MIN DEC128_TRUE_MIN |
标准原文在这一节后半段还给出了人工浮点表示示例,以及符合 ISO/IEC 60559 的 binary32 / binary64 示例宏值;这些示例更多用于说明模型如何落到具体实现,并非新的宏类别。
前向引用:条件包含(6.10.2)、预定义宏名(6.10.10)、复数算术 <complex.h>(7.3)、扩展多字节与宽字符工具 <wchar.h>(7.31)、浮点环境 <fenv.h>(7.6)、通用工具 <stdlib.h>(7.24)、输入输出 <stdio.h>(7.23)、数学 <math.h>(7.12)、ISO/IEC 60559 浮点运算(附录 F)、与 ISO/IEC 60559 兼容的复数运算(附录 G)。