Date: Mon, 20 Sep 2021 08:58:45 +0200
On 20/09/2021 03.00, Jorg Brown via Liaison wrote:
> On Sat, Sep 18, 2021 at 7:12 PM David Olsen via Ext <ext_at_[hidden] <mailto:ext_at_[hidden]>> wrote:
>
> Fred Tydeman wrote:
> >> How about places where 'float' promotes to 'double' and '_Float32' does not promote? Such as printf()?
>
> Good point. Thanks. The proposed rules for floating-point promotion are the same in both languages, where float is the only thing that ever promotes to double. So the difference in usual arithmetic conversions means that:
> printf("%g", (float)1.0 + (_Float32)2.0);
> is undefined behavior in C (because the expression has type _Float32, which does not promote), but
> printf("%g", (float)1.0 + (std::float32_t)2.0);
> is well-formed in C++ (because the expression has type float, which does promote).
>
> I see this as an argument for C to change the rules so that
> float + _Float32 -> float
> Not a compelling argument by itself, but a point in favor of the change.
>
>
> I couldn't believe this was true, but after looking it up in N2596 6.5.2.2, I see:
>
> If the expression that denotes the called function has a type that does not include a prototype,
> the integer promotions are performed on each argument, and arguments that have type float
> are promoted to double. These are called the default argument promotions. If the number of
> arguments does not equal the number of parameters, the behavior is undefined. If the
> function is defined with a type that includes a prototype, and either the prototype ends with
> an ellipsis (, ...) or the types of the argument after promotion are not compatible with the
> types of the parameters, the behavior is undefined.
>
>
> And that's quite alarming; it means that one of these is UB and the other is not, even though float and _Float32 will have the same representation on most of today's compilers:
>
> float fa;
> printf("%g\n", fa);
> _Float32 fb;
> printf("%g\n", fb);
>
> And it also is a pain for anyone wanting to print _Float16 values:
>
> _Float16 f16;
> printf("%g\n", f16); // UB
> printf("%g\n", (double)f16); // OK
> It seems very much against the spirit of the automatic-float-to-double conversion rule, for printf to work with float, but not _Float16 or _Float32 or even _Float64. Surely this was an oversight on C's part? It seems the wording should be changed:
Since there are no printf format specifiers for _FloatN, I think nobody
expects those numbers to be passed to printf in the first place.
I thus find the _FloatN no-promotion-for-varargs rule quite reasonable
in and of itself.
> < arguments that have type float are promoted to double
>> floating-point arguments that have less or equal range and precision than double are promoted to double
>
> (The "or equal" part is possibly unnecessary and reflects my imperfect understanding of the consequences of passing _Float64 to a routine that expects double, including whether those consequences differ from C to C++)
Even with identical layout etc, different types still imply that
accesses cause an aliasing violation, at least in C++.
Jens
> On Sat, Sep 18, 2021 at 7:12 PM David Olsen via Ext <ext_at_[hidden] <mailto:ext_at_[hidden]>> wrote:
>
> Fred Tydeman wrote:
> >> How about places where 'float' promotes to 'double' and '_Float32' does not promote? Such as printf()?
>
> Good point. Thanks. The proposed rules for floating-point promotion are the same in both languages, where float is the only thing that ever promotes to double. So the difference in usual arithmetic conversions means that:
> printf("%g", (float)1.0 + (_Float32)2.0);
> is undefined behavior in C (because the expression has type _Float32, which does not promote), but
> printf("%g", (float)1.0 + (std::float32_t)2.0);
> is well-formed in C++ (because the expression has type float, which does promote).
>
> I see this as an argument for C to change the rules so that
> float + _Float32 -> float
> Not a compelling argument by itself, but a point in favor of the change.
>
>
> I couldn't believe this was true, but after looking it up in N2596 6.5.2.2, I see:
>
> If the expression that denotes the called function has a type that does not include a prototype,
> the integer promotions are performed on each argument, and arguments that have type float
> are promoted to double. These are called the default argument promotions. If the number of
> arguments does not equal the number of parameters, the behavior is undefined. If the
> function is defined with a type that includes a prototype, and either the prototype ends with
> an ellipsis (, ...) or the types of the argument after promotion are not compatible with the
> types of the parameters, the behavior is undefined.
>
>
> And that's quite alarming; it means that one of these is UB and the other is not, even though float and _Float32 will have the same representation on most of today's compilers:
>
> float fa;
> printf("%g\n", fa);
> _Float32 fb;
> printf("%g\n", fb);
>
> And it also is a pain for anyone wanting to print _Float16 values:
>
> _Float16 f16;
> printf("%g\n", f16); // UB
> printf("%g\n", (double)f16); // OK
> It seems very much against the spirit of the automatic-float-to-double conversion rule, for printf to work with float, but not _Float16 or _Float32 or even _Float64. Surely this was an oversight on C's part? It seems the wording should be changed:
Since there are no printf format specifiers for _FloatN, I think nobody
expects those numbers to be passed to printf in the first place.
I thus find the _FloatN no-promotion-for-varargs rule quite reasonable
in and of itself.
> < arguments that have type float are promoted to double
>> floating-point arguments that have less or equal range and precision than double are promoted to double
>
> (The "or equal" part is possibly unnecessary and reflects my imperfect understanding of the consequences of passing _Float64 to a routine that expects double, including whether those consequences differ from C to C++)
Even with identical layout etc, different types still imply that
accesses cause an aliasing violation, at least in C++.
Jens
Received on 2021-09-20 01:58:56