4

Sample code:

#include <stdio.h>
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>

#ifdef FLT16_MAX
_Float16 f16;
int main(void)
{
    printf("%f\n", f16);
    return 0;
}
#endif

Invocation:

# gcc trunk on linux on x86_64
$ gcc t0.c -std=c11 -Wall

Expected diagnostics:

<nothing>

Actual diagnostics:

t0.c:9:14: warning: format '%f' expects argument of type 'double', but argument 2 has type '_Float16' [-Wformat=]
    9 |     printf("%f\n", f16);
      |             ~^     ~~~
      |              |     |
      |              |     _Float16
      |              double

Does it mean that under __STDC_WANT_IEC_60559_TYPES_EXT__ AND if FLT16_MAX defined the gcc is unaware that printf may be used with _Float16? Should it be aware?

Also: printf("%f\n", f); when f is a float leads to no warning above despite the fact that format '%f' expects argument of type 'double', but argument 2 has type 'float'. Confused.

pmor
  • 5,392
  • 4
  • 17
  • 36
  • 2
    A `float` passed to `...` is automatically promoted to `double`. Maybe that doesn't happen for the non-standard `_Float16`? – HolyBlackCat Jan 11 '22 at 20:24
  • 2
    Note that gcc does not provide the implementation of `printf`. It's implemented by the C library, which could be glibc, newlib, musl, or any of a number of others. – Keith Thompson Jan 11 '22 at 20:30
  • 1
    @KeithThompson while it's possible to override, normally a C implementation provides its own standard library, and it generates warnings based on that. – Barmar Jan 11 '22 at 20:32
  • @Barmar gcc in particular is a compiler, not a complete C implementation, and it does not provide an implementation of `printf`. A typical C implementation might include gcc, glibc, binutils, and other components. – Keith Thompson Jan 12 '22 at 00:25
  • @KeithThompson Does it mean that any conforming C compiler can be used with any conforming C library? – pmor Jan 13 '22 at 17:32
  • 1
    @pmor No, the compiler and library have to be compatible. Strictly speaking, as far as the C standard is concerned, there's no such thing as a "conforming compiler" or a "conforming library"; conformance applies to the implementation as a whole. An example: In some versions of MinGW (gcc with Microsoft's library), the compiler and library disagree about the size of `long double`. Neither is wrong, but they don't work correctly together (though there are workarounds). – Keith Thompson Jan 13 '22 at 20:12
  • @KeithThompson Re: "there's no such thing as...": exactly, thanks! Another [example](https://stackoverflow.com/questions/69976945/clang-why-stdc-iec-559-depends-on-include-stdio-h): on Linux both gcc (now seems fixed) and clang define `__STDC_IEC_559__` to `1` in `glibc-2.25/include/stdc-predef.h`, while it is expected to be defined by the compiler itself. Since clang does not define `__GCC_IEC_559`, then `__STDC_IEC_559__` is (incorrectly?) defined to `1` by `stdc-predef.h`. – pmor Jan 14 '22 at 15:37
  • @KeithThompson As a result: under `-ffp-model=fast` (behaves identically to specifying both `-ffast-math` and `ffp-contract=fast`) AND if `stdc-predef.h` is included (as a part of `#include `), then it is unclear, for which purpose the `__STDC_IEC_559__` is defined to `1`. – pmor Jan 14 '22 at 15:38
  • @KeithThompson Re: "while it is expected to be defined by the compiler itself": Hence, the compiler shall know _in advance_ whether its library conforms to the specifications in the annex F. – pmor Jan 14 '22 at 15:45
  • Typo: before: `(incorrectly?)`, after `(unexpectedly)`. – pmor Jan 14 '22 at 16:26

1 Answers1

8

From the clang manual:

Because default argument promotion only applies to the standard floating-point types, _Float16 values are not promoted to double when passed as variadic or untyped arguments. As a consequence, some caution must be taken when using certain library facilities with _Float16; for example, there is no printf format specifier for _Float16, and (unlike float) it will not be implicitly promoted to double when passed to printf, so the programmer must explicitly cast it to double before using it with an %f or similar specifier.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • If "_Float16 values are not promoted to double ...", then does it mean that `printf("%f\n", f16);` triggers UB? – pmor Jan 11 '22 at 20:46
  • 2
    Yes, that's what it means. – Barmar Jan 11 '22 at 20:47
  • Why "Future standardization may include additional floating-point types, including those with greater range, precision, or both than long double" (N2596) and not less range, precision, or both than float? – pmor Jan 11 '22 at 20:49
  • 1
    Who knows. I doubt that's a normative statement, it's just speculation. – Barmar Jan 11 '22 at 20:50
  • 1
    They probably didn't think there would likely be any need for less precision. The direction that computers have been going for decades is bigger, not smaller. – Barmar Jan 11 '22 at 20:51
  • Why the support of `long long` and floating types is mandatory for a conforming implementation targeting hardware with no support of > 32 bit integers nor support of floating-point arithmetic (no FPU)? – pmor Jan 12 '22 at 10:14
  • Please don't ask me to speculate on the decisions of the standards committee. They've probably published a Rationale, I suggest you search for it. – Barmar Jan 12 '22 at 17:04
  • 1) "including those with greater range, precision, or both than long double": this does not mean "excluding those with less range, precision, or both than float". 2) Unexpected that: a) compiler does support `_Float16`, but b) does not support promotion to double in `printf`. It seems that C standard misses this (or similar) requirement: "all the supported additional floating-point types with precision less than double are required to support promotion to double when passed as variadic or untyped arguments". – pmor Jan 13 '22 at 11:37