On Mon, Sep 20, 2021 at 6:17 AM Joseph Myers <joseph@codesourcery.com> wrote:
On Mon, 20 Sep 2021, Jorg Brown wrote:

> 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

See http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_206.htm regarding
why float _Complex does not promote to double _Complex: "This was
intentional because real float promotion to double is in Standard C purely
for compatibility with K&R. Since complex is new, that compatibility is
not an issue, and having it behave like real float would introduce
undesired overhead (and be less like Fortran).".

The same reasoning applies here.  _Float16 and _Float32 were not in K&R C,
so there is no need for any promotions such as were for compatibility with
K&R.

The choice made so far has been not to provide printf support for the new
types at all (instead, strfrom functions are to be used to convert them to
strings, and presumably C++ should provide all the C++-style numeric I/O
and string conversion operations for them).  If printf support were to be
provided (other than through explicitly casting to float / double / long
double), the natural form would probably be to include the N from _FloatN
explicitly in the printf format somewhere.  We have %wN, %wfN printf
length modifiers now for intN_t, int_leastN_t, int_fastN_t (N2680,
accepted at the March 2021 WG14 meeting); it would certainly be possible
if desired to define such modifiers for floating-point formats (e.g.
%w128f to format a _Float128 in the %f style, %w16f for _Float16, etc.).

When the new type int16_t was introduced, we did not force printf users to write "%w16" to use it.  Instead, it naturally up-converts to "int", as part of parameter-passing conventions to printf, because integral parameters are automatically converted to at least "int" when using a parameter of type "...", and the standard guarantees <https://eel.is/c++draft/tab:basic.fundamental.width> that "int" is at least bug enough to support a 16-bit type.

I don't understand what benefit "%w16" has for printf users, given that "%d" will always work, but I don't think it should impact the current decision, since no one is seriously saying that this code should cease to be guaranteed to work, or cause a compile warning for not using "%w16":

uint16_t less_than_64K = func();
printf("func returned %u\n", less_than_64K);

Likewise, I don't see any benefit from not automatically converting lesser-precision binary floating-point types to "double", as currently happens with "float".  Whatever minor processing power is required to convert, say, float16_t to double, it is less than the power needed to convert the "%wf16" characters.  You'd be asking for a lot of library work to handle float16, bfloat16, and float32 types in the printf code, which seems pointless because they will almost certainly simply decide to do the conversion to double in the library, so they can continue to use their existing code.