pab*_*977 7 c language-lawyer c23
新标准C(ISO/IEC 9899:2023,又名C23),
在附录H中,定义了几个宏和类型,
相对于实数和复数算术,
并符合 ISO/IEC 60559 标准(浮点算术)。
根据 H.1 小节,存在三个
实现定义的宏来测试
与附件 H 定义的一致性。
__STDC_IEC_60559_TYPES__
__STDC_IEC_60559_BFP__
__STDC_IEC_60559_DFP__
Run Code Online (Sandbox Code Playgroud)
此外,要“激活”关联的宏和类型,
用户必须定义宏:
__STDC_WANT_IEC_60559_TYPES_EXT__
Run Code Online (Sandbox Code Playgroud)
该标准的措辞在几个细节上很明确:
__STDC_IEC_60559_BFP__是由编译器定义的,则意味着_FloatN,_FloatN_t和其他_FloatN*类型也已定义。__STDC_IEC_60559_DFP__是由编译器定义的,则意味着_DecimalN,_DecimalN_t和其他_DecimalN*类型也已定义。__STDC_IEC_60559_TYPES__无论哪种情况,都会定义宏。__STDC_IEC_60559_TYPES__一个宏__STDC_IEC_60559_BFP__或(或两者)。__STDC_IEC_60559_DFP__在 H.11 小节中,类型long_double_t被添加到 中<math.h>。
long_double_t但是,我无法推断在哪些条件下可以确保给定实现中的存在。
问题:
如果__STDC_IEC_60559_TYPES__已定义,是否足以确定long_double_t也在 中定义<math.h>?
我的怀疑来自以下可能出现的特殊情况:
__STDC_IEC_60559_TYPES__和__STDC_IEC_60559_DFP__已定义,但__STDC_IEC_60559_BFP__未定义。在本例中,定义了十进制类型。
但是,long_double_t不是十进制类型。
子问题:
宏是否__STDC_IEC_60559_BFP__需要存在才能确保存在long_double_t?
评论:
正如 @John Bollinger 在他的回答中解释的那样,和/或宏的
存在
仅确保和存在于 的某些小值。
(我知道这个细节,但我的解释不是最好的。)*BFP__*DFP___FloatN_DecimalNN
TL;DR:依赖一致实现提供的最低基础long_double_t是它定义了宏__STDC_IEC_60559_TYPES__到202311L.
但是,翻译单元还必须__STDC_WANT_IEC_60559_TYPES_EXT__在第一次包含 math.h 之前定义(任何内容),以便实际公开该定义。(C23 H.8/1)
该标准的措辞在几个细节上很明确:
显然不是那么清楚。
作为初步问题,规范说
定义 的实现
__STDC_IEC_60559_TYPES__应202311L符合本附件中的规范。
如果实现没有定义__STDC_IEC_60559_TYPES__该特定值(即使它们将其定义为其他值),则必须理解这一点,以减轻实现与附件中任何内容的一致性。这是一种有意的向前兼容性措施。
该规范继续说道:
实现
__STDC_IEC_60559_TYPES__仅当定义__STDC_IEC_60559_BFP__[...] 或定义时才可以定义__STDC_IEC_60559_DFP__
__STDC_IEC_60559_TYPES__请注意,根据前面的内容,除非精确定义为,否则该规定或附件中的其他任何内容均不适用202311L。否则,就附录 H(C23)而言,所有的赌注都是错误的。例如,一个没有定义__STDC_IEC_60559_TYPES__任何内容并且没有定义__STDC_IEC_60559_BFP__或 的__STDC_IEC_60559_DFP__实现不会因此而失败。
- 如果
__STDC_IEC_60559_BFP__是由编译器定义的,则意味着_FloatN,_FloatN_t和其他_FloatN*类型也已定义。
不完全是。该规范没有将任何需求与__STDC_IEC_60559_BFP__单独定义的实现相关联。除了__STDC_IEC_60559_TYPES__上面讨论的 定义的一般门控之外,规范还明确限制了该领域中定义的后一个宏的一些特定规定。
当满足所有这些条件时,一致的实现会提供类型_Float32和_Float64,并且它们分别相当于float和double。此外,在这些情况下,如果long double对应于某些宽度N大于 64 的 ISO 60559 二进制交换格式之一,则该实现会提供相应的_FloatN类型作为 的等效类型long double。其他_FloatN类型也是允许的,但不是必需的,并且它们的集合是实现定义的。(H.2.1/4)
_FloatN_t其提供的每种类型的 math.h 中都提供了一个遵守本附件规定的一致实现_FloatN。
- 如果
__STDC_IEC_60559_DFP__是由编译器定义的,则意味着_DecimalN,_DecimalN_t和其他_DecimalN*类型也已定义。
同样,实施不受附件中任何内容的约束,除非它们进行了__STDC_IEC_60559_TYPES__适当的定义。在这种情况下,__STDC_IEC_60559_DFP__被定义意味着提供了_Decimal32、_Decimal64、 和。_Decimal128明确允许附加_DecimalN类型,并且此类附加类型的集合是实现定义的。
当附件的规定完全适用时,math.h 将提供_DecimalN_t与_DecimalN实现定义的每一个相对应的。
__STDC_IEC_60559_TYPES__无论哪种情况,都会定义宏。
不,没有这样的要求。逻辑是相反的。__STDC_IEC_60559_TYPES__正如已经讨论过的,除非适当定义,否则附件 H 均不适用。如果是,那么至少还必须定义其他两个宏之一,但其中一个定义的宏并不是得出有关 的任何结论的基础__STDC_IEC_60559_TYPES__。
- 如果定义了宏,则意味着至少定义了
__STDC_IEC_60559_TYPES__一个宏__STDC_IEC_60559_BFP__或 (或两者)。__STDC_IEC_60559_DFP__
更具体地说,这仅适用__STDC_IEC_60559_TYPES__于精确定义为 的情况202311L。
如果
__STDC_IEC_60559_TYPES__定义了,是否足以确保long_double_t<math.h> 中也定义了 ?
__STDC_IEC_60559_TYPES__准确定义宏202311L足以确保其long_double_t在实现中可用。附件没有对此提出任何附加条件。然而,该计划确实需要选择加入。C23 H.8/1:
__STDC_WANT_IEC_60559_TYPES_EXT__仅当宏(由用户)在代码中首次包含相应标头的位置定义时,由本附件添加到库标头的标识符才由其各自的标头定义或声明。
你写了:
我的怀疑来自以下可能出现的特殊情况:
__STDC_IEC_60559_TYPES__和__STDC_IEC_60559_DFP__已定义,但__STDC_IEC_60559_BFP__未定义。在本例中,定义了十进制类型。
真的。
但是,
long_double_t不是十进制类型。
谁说?C23 6.2.6.1/1:
除本节中所述外,所有类型的表示形式均未指定。
该子条款没有定义任何 FP 类型的表示。
没有要求long double要么long_double_t二进制类型。似乎甚至没有要求这两种类型是等效的,尽管我希望这是实现质量的问题。
long_double_t但即使是二进制类型也没有问题。__STDC_IEC_60559_BFP__未定义并不意味着该实现不提供任何二进制 FP 类型。这仅意味着该实现拒绝承诺其符合附件 H 有关二进制 FP 类型的所有规定。
宏是否
__STDC_IEC_60559_BFP__必须存在才能确保 的存在long_double_t?
否。 H.11/6 指定long_double_t可从 math.h 获得,但须遵守上面讨论的程序选择加入,并且除了附件中所有内容__STDC_IEC_60559_TYPES__所依据的相同功能测试宏之外,不以任何其他方式为条件。因此,如果一致的实现定义为,则其 math.h 定义为那些选择加入的程序。__STDC_IEC_60559_TYPES__202311Llong_double_t