除了其他答案之外,这里还有一些关于 GCC 中 printf 格式检查的更多信息:
当您说__attribute__((__format__ (FORMAT, ...)))
时, 的值FORMAT
可以是(就 printf 而言)以下之一:printf
, gnu_printf
, ms_printf
.
ms_printf
使 GCC 假定该函数采用用于 Microsoft Visual Studio CRT printf 系列函数的格式字符串。这意味着 GCC 会抱怨z
,hh
和ll
, 但会I64
毫无警告地通过。
gnu_printf
让 GCC 在下面假设 GNU libc printf 实现(或者可能只是一个 POSIX/C99 兼容的 printf 实现,我不确定)。因此 GCC 会抱怨I64
和其他微软扩展,但会接受z
,hh
和ll
.
printf
是ms_printf
编译 Windows 时的别名,gnu_printf
否则是别名。
请注意,此检查与正在使用的实际 printf 实现完全正交。如果您编写自己的类似 printf 的函数并__attribute__((__format__ (FORMAT, ...)))
使用它,这很容易看出 - GCC 会根据FORMAT
.
我知道的可用 printf 实现:
- MinGW.org 和 MinGW-w64 工具链中的MinGW ANSI STDIO(用 编译
-D__USE_MINGW_ANSI_STDIO=1
)。符合ms_printf
(完全?)和gnu_printf
格式(部分 - 不支持位置参数)。
- MSVCRT(不带 编译
-D__USE_MINGW_ANSI_STDIO=1
)。符合ms_printf
(duh ...),符合性gnu_printf
非常低,并且取决于运行时版本(旧版本不支持ll
,新版本支持;到目前为止,任何版本都不支持;GCC 很幸运地没有意识到这些发展,z
并且hh
假设最坏的情况,似乎是 VC 6.0 时代的 msvcrt)。
- gnulib。符合
ms_printf
并gnu_printf
完全(或接近完全)。
MinGW.org 中的stdio.h
标头不使用attribute format
.
stdio.h
MinGW-w64 中的标头attribute format gnu_printf
用于 MinGW ANSI STDIO 实现,但不用于 MSVCRT 实现。已修复:在较新版本的 MinGW-w64 标头中,stdio.h
将attribute format ms_printf
用于 MSVCRT 实现。
printf
gnulib 完全了解and之间的区别gnu_printf
,并且会根据一些复杂的宏来选择一个或另一个(大概伴随着一个支持格式所说的内容的正确实现)。
已知(目前)存在 GCC 格式检查问题的软件:
- glib - 使用
printf
格式,但实现来自 gnulib;将其更改为有一个突出的错误gnu_printf
- CPython - 代码
z
格式丰富,但官方二进制文件是针对 MSVCRT 构建的;它还printf
在其扩展标头中使用格式,即使扩展也经常z
使用