GCC:为什么在使用-std=c11 -Wall编译时无法编译干净的printf(“%f \ n”,f16)?

4

示例代码:

#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

调用:

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

期望的诊断结果:

<nothing>

实际诊断:

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
__STDC_WANT_IEC_60559_TYPES_EXT__ 如果被定义,并且 FLT16_MAX 被定义,那么 gcc 不知道 _Float16 是否可以与 printf 一起使用吗?它应该知道吗?
此外:ffloat 类型时,printf("%f\n", f);不会导致上述警告,尽管“格式 '%f' 期望类型为 'double' 的参数,但第二个参数的类型为 'float'”。令人困惑。

2
传递给 ...float 类型将自动提升为 double 类型。也许对于非标准的 _Float16 类型不会发生这种情况? - HolyBlackCat
2
请注意,gcc不提供printf的实现。它是由C库实现的,可能是glibc、newlib、musl或其他库之一。 - Keith Thompson
1
@KeithThompson 虽然可以覆盖,但通常 C 实现会提供自己的标准库,并基于此生成警告。 - Barmar
1
@pmor 不,编译器和库必须兼容。严格来说,就C标准而言,不存在所谓的“符合标准的编译器”或“符合标准的库”,符合性适用于整个实现。例如:在某些MinGW版本(使用Microsoft库的gcc)中,编译器和库对于“long double”的大小存在分歧。两者都没有错,但它们不能正确地配合使用(尽管有解决方法)。 - Keith Thompson
笔误:之前:(错误地?),之后:(意外地) - pmor
显示剩余5条评论
1个回答

9
clang手册中得知:
因为默认参数提升仅适用于标准浮点类型,所以当作为可变参数或未指定类型的参数传递时,_Float16值不会被提升为double。因此,在使用某些库设施时必须注意使用_Float16;例如,没有_Float16的printf格式说明符,并且(与float不同),它在传递给printf时不会被隐式提升为double,因此程序员必须在使用与%f类似的说明符之前将其显式转换为double。

如果“_Float16值不会提升为double ...”,那么printf(“%f \ n”,f16);是否会触发UB? - pmor
2
是的,这就是它的意思。 - Barmar
为什么“未来的标准化可能包括更多浮点类型,包括比long double具有更大范围、精度或两者都更高的类型”(N2596),而不是比float范围、精度或两者都更低的类型? - pmor
1
谁知道呢。我怀疑那不是规范性的陈述,只是猜测而已。 - Barmar
1
他们可能没有想到会有减少精度的需求。计算机发展数十年来的趋势是变得更大,而不是更小。 - Barmar
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接