除了其他答案之外,这里还有一些关于 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.hMinGW-w64 中的标头attribute format gnu_printf用于 MinGW ANSI STDIO 实现,但不用于 MSVCRT 实现。已修复:在较新版本的 MinGW-w64 标头中,stdio.h将attribute format ms_printf用于 MSVCRT 实现。
printfgnulib 完全了解and之间的区别gnu_printf,并且会根据一些复杂的宏来选择一个或另一个(大概伴随着一个支持格式所说的内容的正确实现)。
已知(目前)存在 GCC 格式检查问题的软件:
- glib - 使用
printf格式,但实现来自 gnulib;将其更改为有一个突出的错误gnu_printf
- CPython - 代码
z格式丰富,但官方二进制文件是针对 MSVCRT 构建的;它还printf在其扩展标头中使用格式,即使扩展也经常z使用