long_double_t 是否存在(标准 C: C23)

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

链接到 C23 标准草案

Joh*_*ger 2

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,并且它们分别相当于floatdouble。此外,在这些情况下,如果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