The new standard C (ISO/IEC 9899:2023, aka C23),
in the Annex H, several macros and types are defined,
relative to real and complex arithmetic,
subject to the standard ISO/IEC 60559
(floating-point arithmetic).
According to subsection H.1, there are three
implementation-defined macros to test conformance
with the definitions of Annex H.
__STDC_IEC_60559_TYPES__
__STDC_IEC_60559_BFP__
__STDC_IEC_60559_DFP__
In addition, to "activate" the associated macros and types,
the user has to define the macro:
__STDC_WANT_IEC_60559_TYPES_EXT__
The wording of the standard is clear in several details:
__STDC_IEC_60559_BFP__
is defined by the compiler, it implies that _FloatN
, _FloatN_t
and other _FloatN*
types are defined.__STDC_IEC_60559_DFP__
is defined by the compiler, it implies that _DecimalN
, _DecimalN_t
and other _DecimalN*
types are defined.__STDC_IEC_60559_TYPES__
is defined.__STDC_IEC_60559_TYPES__
is defined, it means that at least one of the macros __STDC_IEC_60559_BFP__
or __STDC_IEC_60559_DFP__
(or both) is defined.In subsection H.11, the type long_double_t
is added to <math.h>
.
However, I cannot deduce under which conditions one can ensure the existence of long_double_t
in a given implementation.
QUESTION:
If __STDC_IEC_60559_TYPES__
is defined,
is it enough to be sure that long_double_t
is also defined in <math.h>
?
My doubt comes from the following particular case that could arise:
__STDC_IEC_60559_TYPES__
and __STDC_IEC_60559_DFP__
are defined, but __STDC_IEC_60559_BFP__
is not defined.In this case, decimal types are defined.
However, long_double_t
is not a decimal type.
SUB-QUESTION:
Is the macro __STDC_IEC_60559_BFP__
required to exist in order to ensure existence of long_double_t
?
COMMENTS:
As @John Bollinger explains in his answer,
the existence of *BFP__
and/or *DFP__
macros
only ensures that _FloatN
and _DecimalN
exist
for certain small values of N
.
(I was aware of that detail, but my explanation was not the best.)
TL;DR: the minimum basis for relying on a conforming implementation to provide long_double_t
is that it defines macro __STDC_IEC_60559_TYPES__
to 202311L
.
However, the translation unit must also define __STDC_WANT_IEC_60559_TYPES_EXT__
(to anything) before including math.h for the first time for that definition to actually be exposed. (C23 H.8/1)
The wording of the standard is clear in several details:
Apparently not so clear.
As a preliminary matter, the spec says
An implementation that defines
__STDC_IEC_60559_TYPES__
to202311L
shall conform to the specifications in this annex.
This must be understood to relieve implementations from conforming to anything in the annex if they do not define __STDC_IEC_60559_TYPES__
to that specific value (even if they define it to some other value). This is an intentional forward-compatibility measure.
The spec goes on to say:
An implementation may define
__STDC_IEC_60559_TYPES__
only if it defines__STDC_IEC_60559_BFP__
[...] or defines__STDC_IEC_60559_DFP__
Note well that per the previous, neither that provision nor anything else in the annex applies unless __STDC_IEC_60559_TYPES__
is defined to exactly 202311L
. Otherwise, all bets are off as far as Annex H (of C23) is concerned. For example, an implementation that defined __STDC_IEC_60559_TYPES__
to nothing, and did not define either __STDC_IEC_60559_BFP__
or __STDC_IEC_60559_DFP__
, would not for that reason fail to conform.
- If
__STDC_IEC_60559_BFP__
is defined by the compiler, it implies that_FloatN
,_FloatN_t
and other_FloatN*
types are defined.
Not exactly. The spec does not associate any requirements with an implementation defining __STDC_IEC_60559_BFP__
alone. In addition to the general gating by definition of __STDC_IEC_60559_TYPES__
, discussed above, the spec explicitly conditions some of the particular provisions in this area on the latter macro being defined.
When all those conditions are met, a conforming implementation provides types _Float32
and _Float64
, and those are equivalent to float
and double
, respectively. Also, under those circumstances, if long double
corresponds to one of the ISO 60559 binary exchange formats for some width N greater than 64, then the implementation provides the corresponding _FloatN
type as an equivalent to long double
. Other _FloatN
types are allowed, but not required, and the set of them is implementation-defined. (H.2.1/4)
A conforming implementation that binds itself to the provisions of this annex provides _FloatN_t
in its math.h for each _FloatN
type it provides.
- If
__STDC_IEC_60559_DFP__
is defined by the compiler, it implies that_DecimalN
,_DecimalN_t
and other_DecimalN*
types are defined.
Again, implementations are not bound to anything in the annex unless they define __STDC_IEC_60559_TYPES__
appropriately. In that case, __STDC_IEC_60559_DFP__
being defined implies that _Decimal32
, _Decimal64
, and _Decimal128
are provided. Additional _DecimalN
types are explicitly allowed, and that the set of such additional types is implementation defined.
When the provisions of the annex apply at all, math.h will provide a _DecimalN_t
corresponding to each _DecimalN
that the implementation defines.
- In either case, the macro
__STDC_IEC_60559_TYPES__
is defined.
No, there is no such requirement. The logic is the other way around. As already discussed, none of Annex H applies unless __STDC_IEC_60559_TYPES__
is defined appropriately. If it is, then at least one of the other two macros must also be defined, but one of those being defined is not a basis for concluding anything about __STDC_IEC_60559_TYPES__
.
- If the macro
__STDC_IEC_60559_TYPES__
is defined, it means that at least one of the macros__STDC_IEC_60559_BFP__
or__STDC_IEC_60559_DFP__
(or both) is defined.
More specifically, this applies only if __STDC_IEC_60559_TYPES__
is defined to exactly 202311L
.
If
__STDC_IEC_60559_TYPES__
is defined, is it enough to be sure thatlong_double_t
is also defined in <math.h>?
Macro __STDC_IEC_60559_TYPES__
being defined to exactly 202311L
is enough to be sure that long_double_t
is available from the implementation. The annex does not place any additional conditions on that. The program does need to opt in, however. C23 H.8/1:
The identifiers added to library headers by this annex are defined or declared by their respective headers only if the macro
__STDC_WANT_IEC_60559_TYPES_EXT__
is defined (by the user) at the point in the code where the appropriate header is first included.
You wrote:
My doubt comes from the following particular case that could arise:
__STDC_IEC_60559_TYPES__
and__STDC_IEC_60559_DFP__
are defined, but__STDC_IEC_60559_BFP__
is not defined.In this case, decimal types are defined.
True.
However,
long_double_t
is not a decimal type.
Who says? C23 6.2.6.1/1:
The representations of all types are unspecified except as stated in this subclause.
That subclause does not define the representation of any FP types.
There is no requirement that either long double
or long_double_t
be a binary type. There seems not even to be a requirement that those two types be equivalent, though I would expect that as a quality of implementation matter.
But there is no problem even if long_double_t
is a binary type. __STDC_IEC_60559_BFP__
not being defined does not imply that the implementation does not provide any binary FP types. It means only that the implementation declines to promise that it conforms to all the provisions of Annex H with regard to binary FP types.
Is the macro
__STDC_IEC_60559_BFP__
required to exist in order to ensure existence oflong_double_t
?
No. H.11/6 specifies that long_double_t
is available from math.h, subject to program opt-in as discussed above, and that is not otherwise conditioned on anything other than the same __STDC_IEC_60559_TYPES__
feature test macro on which everything in the annex is conditioned.
Thereore, if a conforming implementation defines __STDC_IEC_60559_TYPES__
to 202311L
then its math.h defines long_double_t
to those programs that opt in.