5.2.4 环境限制
1、翻译与执行环境都约束了语言翻译器和库的实现。下面概述了对一个顺应标准实现的语言相关的环境限制;库相关的限制在条款7中讨论。
5.2.4.1 翻译限制
1、实现应该能够翻译并执行至少一个程序,该程序包含以下每个限制的至少一个实例:[注:实现应该尽量避免强加使用固定的翻译限制。]
—— 127个语句块的嵌套层级
—— 63个带条件的包含嵌套层级
—— 12个指针、数组与函数声明符(以任意结合)在一个声明中用于修饰一个算术、结构体、联合体或void类型。
—— 63个圆括号包围的声明符的嵌套层级,在一个完整的声明符内
—— 63个圆括号包围的表达式的嵌套层级,在一个完整的表达式内
—— 63个有效初始字符,在一个内部标识符或一个宏名中(每个通用字符名或扩展源字符被认作为一单个字符)
—— 31个有效初始字符,在一个外部标识符中(每个通用字符名指定了一个0000FFFF或更小的short类型标识符,被认作为6个字符,每个通用字符名指定了00010000或更大的short类型标识符被认作为10个字符,并且每个扩展源字符被认作为与相应的通用字符名相同的字符个数,如果存在的话)[注:见6.11.3]
—— 4095个外部标识符,一个翻译单元中
—— 127个形参,在一个函数定义中
—— 127个实参,在一个函数调用中
—— 127个形参,在一个宏定义中
—— 127个实参,在一个宏调用中
—— 4095个字符,在一个逻辑源行中
—— 4095个字符,在一个字符串字面量中(在字符串拼接之后)
—— 65535个字节,在一个对象中(仅在一个宿主环境中)
—— 15个#include文件的嵌套层级
—— 1023个case标签,对于一条switch语句(不包括任一嵌套的switch语句)
—— 1023个成员,在一单个结构体或联合体中
—— 1023个枚举常量,在一单个枚举中
—— 63个结构体或联合体定义的嵌套层级,在一单个结构体声明列表中
5.2.4.2 数值限制
1、一个实现要求对所有在本条款中所指定的限制进行文档化,这些在头文件<limits.h>和<float.h>中指定。额外的限制在<stdint.h>中指定。
5.2.4.2.1 整数类型的大小<limits.h>
1、下面所给定的值应该用适合于#if预处理指示符中的常量表达式来代替。此外,除了CHAR_BIT和MB_LEN_MAX,下面应该用具有相同类型的表达式来代替,作为一个表达式会是一个根据整数晋升所转换的相应类型的对象。它们的实现定义的值应该大于等于那些所展示的量级(绝对值),带有相同的符号。[译者注:标准这里指明了以下所定义的某个整数类型的最小值最大值在实际实现中要大于等于下面所定义的量级(绝对值)。在一般32位/64位系统的实现中,像SCHAR_MIN被定义为-128;SHRT_MIN被定义为-65536;INT_MIN被定义为-32768。]
——不作为一个位域的最小对象的比特数(字节)
CHAR_BIT 8
——signed char类型的一个对象的最小值
SCHAR_MIN -127 // -(27 - 1)
——signed char类型的一个对象的最大值
SCHAR_MAX +127 // (27 - 1)
——unsigned char类型的一个对象的最大值
UCHAR_MAX 255 // 28 - 1
——char类型的一个对象的最小值
CHAR_MIN 见下面
——char类型的一个对象的最大值
CHAR_MAX 见下面
——一个多字节字符中的最大字节个数,对于任一支持区域
MB_LEN_MAX 1
——short int类型的一个对象的最小值
SHRT_MIN -32767 // -(215 - 1)
——short int类型的一个对象的最大值
SHRT_MAX +32767 // 215 - 1
——unsigned short int类型的一个对象的最大值
USHRT_MAX 65535 // 216 - 1
——int类型的一个对象的最小值
INT_MIN -32767 // -(215 - 1)
——int类型的一个对象的最大值
INT_MAX +32767 // (215 - 1)
——unsigned int类型的一个对象的最大值
UINT_MAX 65535 // 216 - 1
——long int类型的一个对象的最小值
LONG_MIN -2147483647 // (-231 - 1)
——long int类型的一个对象的最大值
LONG_MAX +2147483647 // 231 -1
——unsigned long int类型的一个对象的最大值
ULONG_MAX 4294967295 // 232 - 1
——long long int类型的一个对象的最小值
LLONG_MIN -9223372036854775807 // -(263 - 1)
——long long int类型的一个对象的最大值
LLONG_MAX +9223372036854775807 // 263 - 1
——unsigned long long int类型的一个对象的最大值
ULLONG_MAX 18446744073709551615 // 264 - 1
2、如果当使用一个表达式时char类型的一个对象的值被对待为一个带符号的整数,那么CHAR_MIN值应该与SCHAR_MIN值相同,并且CHAR_MAX值应该与SCHAR_MAX值相同。否则,CHAR_MIN值应该是0,且CHAR_MAX值应该与UCHAR_MAX值相同。[注:见6.2.5]UCHAR_MAX值应该等于2CHAR_BIT - 1。
5.2.4.2.2 浮点类型的特征<float.h>
1、浮点类型的特征依据描述浮点数的一个表示并提供关于一个实现的浮点算术的信息的值的一个模型来定义。[注:浮点模型目的在于阐明每个浮点特征的描述,而且不要求实现的浮点算术要与标准完全一致。]以下参数用于定义每个浮点类型的模型:
s 符号位(±1)
b 指数表示的基或基数(一个大于1的整数)
e 指数(在一个最小值emin与一个最大值emax之间的一个整数)
p 精度(尾数中的基b数字的个数)
fk 小于b的非负整数(尾数数字)
2、一个浮点数(x)由以下模型进行定义:
3、除了规格化的浮点数(f1 > 0,若x ≠ 0)之外,浮点可以包含其它类型的浮点数,诸如次正规浮点数(subnormal floating-numbers, x ≠ 0, e > emin, f1 = 0);以及非浮点数,诸如无穷数以及NaN(非数)。NaN是对一个不是一个数字的编码。一个安静的NaN通过几乎每一个算术操作进行传播而不会引发一个浮点异常;一个发送信号的NaN在当它作为一个算术操作数而发生的时候引发一个浮点异常。
4、一个实现可以把一个符号给予零或不是浮点数(诸如无穷数和NaN)的值,或者将它们保留为无符号。无论这些值在什么情况下是无符号的,在此国际标准中有任一要取回符号的要求都应该产生一个未指定的符号,并且对于设置符号的任一要求都应该被忽略。
5、对于一个浮点类型,可表示的值的最小范围是从在那个类型中可表示的最大负有限浮点数到在那个类型中可表示的最大正有限浮点数。此外,如果负无穷数载一个类型中可被表示,那么那个类型的范围被扩展到所有负实数;类似地,如果正无穷数在一个类型中可被表示,那么那个类型的范围被扩展到所有正实数。
6、浮点操作(+,-,*,/)的精度以及<math.h>和<complex.h>中库函数所返回的浮点结果的精度是由实现定义的,正如浮点内部表示与由<stdio.h>、<stdlib.h>和<wchar.h>中库函数所执行的字符串表示之间的转换精度一样。实现可以声明精度是未知的。
7、在<float.h>头文件中的所有整数,除了FLT_ROUNDS,应该是适合于在#if预处理指示符中所使用的常量表达式;所有浮点值都应该是常量表达式。对于所有三种浮点类型,除了DECIMAL_DIG、FLT_EVAL_METHOD、FLT_RADIX以及FLT_ROUNDS之外,所有浮点值都具有独立的名字。除了FLT_EVAL_METHOD和FLT_ROUNDS之外,给所有值提供了浮点模型表示。
8、浮点数加法的取整模式由实现定义的FLT_ROUNDS值来描述其特征:[注:FLT_ROUNDS的计算正确地反映了通过<fenv.h>中的fesetround函数的任一执行时取整模式的改变。]
-1 不能决定的
0 向零取整
1 最近取整
2 向正无穷大取整
3 向负无穷大取整
FLT_ROUNDS的其它值描述了实现自定义的取整行为。
9、除了对赋值及投射(投射移除了所有额外的范围与精度)以外,由带有浮点操作数的操作符所产生的值以及受通常算术转换和浮点常量转换影响的值被计算为一种格式,其范围和精度可以大于该类型所要求的。计算格式的使用通过实现自定义的FLT_EVAL_METHOD的值进行描述:[注:此计算方法确定了涉及到所有浮点类型的表达式,而不仅仅是实数。比如,如果FLT_EVAL_METHOD为1,那么两个float _Complex操作数的积用double _Complex格式来表示,并且其部分被计算为double。]
-1 不能决定的;
0 计算所有操作与常量正好到该类型的范围与精度;
1 计算所有float和double类型的操作和常量到double类型的范围与精度,计算long double的操作与常量到long double类型的范围与精度;
2 计算所有操作与常量到long double类型的范围与精度。
FLT_EVAL_METHOD的其它所有负数值描述了实现自定义的行为。
10、是否存在次正规浮点数是由实现自定义的FLT_HAS_SUBNORM、DBL_HAS_SUBNORM以及LDBL_HAS_SUBNORM来描述的:
-1 不能决定的;[注:不能决定的描述目的在于,浮点操作不一贯地将次正规表示解释为零或是非零的情况。]
0 不存在[注:不存在的描述目的在于,没有浮点操作会从非次正规输入产生次正规结果的情况,即使类型格式包含了次正规数的表示。](类型不支持次正规数)
1 存在(类型支持次正规数)
11、在以下列表中所给出的值应该用具有实现自定义的值的常量表达式来代替,这些值大于等于那些所展示出来的量级(绝对值),含带符号:
——指数表示的基数,b
FLT_RADIX
——浮点尾数中基FLT_RADIX数字的个数,p
FLT_MANT_DIG
DBL_MANT_DIG
LDBL_MANT_DIG
——十进制数的个数,n,比如任一带有p基数b个数字的浮点数可以被舍入到带有n个十进制数的浮点数,并且对值不做任何改变再次返回去,
FLT_DECIMAL_DIG 6
DBL_DECIMAL_DIG 10
LDBL_DECIMAL_DIG 10
——十进制数的个数,n,比如支持带有pmax基数b个数字的浮点类型的最大浮点数可以被舍入到带有n个十进制数的浮点个数并且不改变到那个值而再次返回去,
DECIMAL_DIG 10
——十进制数字的个数,q,比如带有q个十进制数字的浮点数可以被舍入到带有基数为p,b个数字浮点数,并且在不改变到q个十进制的情况下再次返回去。
FLT_DIG 6
DBL_DIG 10
LDBL_DIG 10
——最小负整数,比如FLT_RADIX提升到小于幂是一个规格化的浮点数emin的整数。
FLT_MIN_EXP
DBL_MIN_EXP
LDLB_MIN_EXP
——最小负整数,比如10提升到幂在规格化浮点数范围内,
FLT_MIN10_EXP -37
DBL_MIN_10_EXP -37
LDLB_MIN_10_EXP -37
——最大整数,比如FLT_RADIX提升到小于幂是一个可表示的有限浮点数emax的整数。
FLT_MAX_EXP
DBL_MAX_EXP
LDBL_MAX_EXP
——最大整数,比如10提升到幂在可表示的浮点数的范围内的整数,
FLT_MAX_10_EXP +37
DBL_MAX_10_EXP +37
LDBL_MAX_10_EXP +37
12、在以下列表中给出的值应该用带有实现自定义的值的常量表达式来代替,这些值大于等于以下所展示的:
——最大可表示的有限浮点数,(1 - b-p)bemax
FLT_MAX 1E+37
DBL_MAX 1E+37
LDBL_MAX 1E+37
13、以下列表中所给出的值应该用带有实现定义的(正数)值的常量表达式来代替,这些值小于等于下面所展示的:
——在所给的浮点类型中可表示的在1与大于1的最小值之间的差,b1-p
FLT_EPSILON 1E-5
DBL_EPSILON 1E-9
LDBL_EPSILON 1E-9
——最小规格化的正浮点数,bemin-1
FLT_MIN 1E-37
DBL_MIN 1E-37
LDBL_MIN 1E-37
——最小正浮点数[注:如果次正规数是否存在不可确定,那么该值目的在于作为一个不大于那个类型的最小规格化正数的正数。]
FLT_TRUE_MIN 1E-37
DBL_TRUE_MIN 1E-37
LDBL_TRUE_MIN 1E-37
推荐实践
14、(至少)从double到用DECIMAL_DIG数字的十进制数的转换和转换回应该是同一个函数。
15、例1 以下描述了满足本标准最低要求的人工浮点表示,以及在一个<float.h>头文件中针对float类型的适当的值:
FLT_RADIX 16
FLT_MANT_DIG 6
FLT_EPSILON 9.53674316E-07F
FLT_DECIMAL_DIG 9
FLT_DIG 6
FLT_MIN_EXP -31
FLT_MIN 2.93873588E-39F
FLT_MIN_10_EXP -38
FLT_MAX_EXP +32
FLT_MAX 3.40282347E+38F
FLT_MAX_10_EXP +38
16、例2 以下描述了也满足IEC60559[注:在此标准中的浮点模型从零对b的幂求和,因此指数限制的值是小于这里所展示的。]中的单精度和双精度数要求的浮点表示,以及在一个<float.h>头文件中对于float和double类型的适当的值:
FLT_RADIX 2
DECIMAL_DIG 17
FLT_MANT_DIG 24
FLT_EPSILON 1.19209290E-07E // 十进制数常量
FLT_EPSILON 0X1P-23F // 十六进制常量
FLT_DECIMAL_DIG 9
FLT_DIG 6
FLT_MIN_EXP -125
FLT_MIN 1.17549435E-38F // 十进制数常量
FLT_MIN 0X1P-126F // 十六进制常量
FLT_TRUE_MIN 1.40129846E-45F // 十进制数常量
FLT_TRUE_MIN 0X1P-149F // 十六进制常量
FLT_HAS_SUBNORM 1
FLT_MIN_10_EXP -37
FLT_MAX_EXP +128
FLT_MAX 3.40282347E+38F // 十进制常量
FLT_MAX 0X1.fffffeP127F // 十六进制常量
FLT_MAX_10_EXP +38
DBL_MANT_DIG 53
DBL_EPSILON 2.2204460492503131E-16 // 十进制常量
DBL_DECIMAL_DIG 17
DBL_DIG 15
DBL_MIN_EXP -1021
DBL_MIN 2.2250738585072014E-308 // 十进制常量
DBL_MIN 0X1P-1022 // 十六进制常量
DBL_TRUE_MIN 4.9406564584124654E-324 // 十进制数常量
DBL_TRUE_MIN 0X1P-1074 // 十六进制常量
DBL_HAS_SUBNORM 1
DBL_MIN_10_EXP -307
DBL_MAX_EXP +1024
DBL_MAX 1.7976931348623157E+308 // 十进制常量
DBL_MAX 0X1.fffffffffffffP1023 // 十六进制常量
DBL_MAX_10_EXP +308
如果支持一个类型比double更宽,那么DECIMAL_DIG应该大于17。比如,如果最宽类型要使用最小宽度的IEC60559双精度扩展格式(64位精度),那么DECIMAL_DIG将是21。