GCC:为什么不能在 -std=c11 -Wall 下编译干净的 printf("%f\n", f16)?
GCC: why cannot compile clean printf("%f\n", f16) under -std=c11 -Wall?
示例代码:
#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 不知道 printf
可以与 _Float16
一起使用?它应该知道吗?
另外:printf("%f\n", f);
当 f
是 float
时,尽管 format '%f' expects argument of type 'double', but argument 2 has type 'float'
没有上面的警告。困惑。
来自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.
示例代码:
#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 不知道 printf
可以与 _Float16
一起使用?它应该知道吗?
另外:printf("%f\n", f);
当 f
是 float
时,尽管 format '%f' expects argument of type 'double', but argument 2 has type 'float'
没有上面的警告。困惑。
来自clang manual:
Because default argument promotion only applies to the standard floating-point types,
_Float16
values are not promoted todouble
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 noprintf
format specifier for_Float16
, and (unlikefloat
) it will not be implicitly promoted todouble
when passed toprintf
, so the programmer must explicitly cast it to double before using it with an%f
or similar specifier.