【问题标题】:Why does GCC show duplicate warnings for bad printf format specifier?为什么 GCC 会针对错误的 printf 格式说明符显示重复警告?
【发布时间】:2011-09-11 20:04:43
【问题描述】:

我很好奇为什么 GCC 在编译此文件时显示两个相同的警告:

$ cat test.c 
#include <stdio.h> 

int main (int argc, char const *argv[])
{
    long foo = 0l;
    printf("%i\n", foo);

    return 0;
}
$ gcc-4.2 -Wall test.c 
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’

有趣的是,Clang 还给出了两个警告:

$ clang test.c 
test.c:6:14: warning: conversion specifies type 'int' but the argument has type 'long' [-Wformat]
    printf("%i\n", foo);
            ~^     ~~~
            %ld
test.c:6:14: warning: conversion specifies type 'int' but the argument has type 'long' [-Wformat]
    printf("%i\n", foo);
            ~^     ~~~
            %ld
2 warnings generated.

有什么想法吗?


信息:

$ gcc-4.2 -v
Using built-in specs.
Target: i686-apple-darwin11
Configured with: /private/var/tmp/gcc/gcc-5666.3~278/src/configure
--disable-checking --enable-werror --prefix=/usr --mandir=/share/man
--enable-languages=c,objc,c++,obj-c++
--program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib
--build=i686-apple-darwin11 --program-prefix=i686-apple-darwin11-
--host=x86_64-apple-darwin11 --target=i686-apple-darwin11
--with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)

$ clang -v
Apple clang version 2.1 (tags/Apple/clang-163.7.1) (based on LLVM 3.0svn)
Target: x86_64-apple-darwin11.1.0
Thread model: posix

编辑:一些人提出的“多架构”假设听起来不错,但我不确定它是否正确。如果我使用-arch 强制使用单一架构,我会收到两个警告。如果我指定-arch x86_64 -arch i386,我会收到两组重复警告!

$ gcc-4.2 -Wall -arch x86_64 test.c 
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’

$ gcc-4.2 -Wall -arch x86_64 -arch i386 test.c 
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c: In function ‘main’:
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’

编辑:我没有得到所有警告类型的欺骗。 -Wformat 是迄今为止我遇到的唯一一个。例如,如果我输入一个未使用的变量,我只会收到一个警告:

$ cat test.c 
#include <stdio.h> 

int main (int argc, char const *argv[])
{
    long foo = 0l;
    long bar;
    printf("%i\n", foo);

    return 0;
}

$ gcc-4.2 -Wall test.c 
test.c: In function ‘main’:
test.c:7: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:7: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘long int’
test.c:6: warning: unused variable ‘bar’

【问题讨论】:

  • FWIW,当我使用 GCC 4.1.2 时,我只收到一条错误消息。你确定这不是你的构建系统的产物,它以某种方式调用了 GCC 两次?
  • 谢谢奥利。我完全不确定,可能是这样。 :-/
  • 我没有看到重复的警告。但是,无论如何,这是一个你应该修复的警告,所以......
  • 我在 Ubuntu 11.04 上收到 gcc 4.5.2 和 clang 2.8 的一个警告。

标签: c gcc compilation clang


【解决方案1】:

这是因为 Apple 的 stdio.h 标头将 GCC format attribute 附加到其声明的 printf()...

(例如,参见printf()here 的声明和__printflike()here 的声明)

...但是 GCC(和 Clang,因为它试图与 GCC 非常兼容!)已经内置了 printf() 是一个接受 printf 风格参数的函数的知识。由于内置知识,您会收到一个警告,而由于显式属性,您会收到第二个警告。

您可以通过自己做同样的事情在其他平台(至少有几个版本的 GCC)上展示相同的行为:

extern int printf(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));

int main (int argc, char const *argv[])
{
    long foo = 0l;
    printf("%i\n", foo);

    return 0;
}

【讨论】:

  • 太棒了!问题解决了。 (您还可以通过从/usr/include/stdio.h 中的printf 的定义中删除`__DARWIN_LDBL_COMPAT(printf) __printflike(1, 2)` 然后重新编译来证明这是正确的答案。)
【解决方案2】:

如果您针对两种 CPU 架构(例如 iOS 上的 ARMv6/ARMv7 或 Mac 上的 i386/x86_64),您将看到每个警告的两个副本,因为编译器会为每个文件运行两次(每个文件运行一次)架构。)

在 Mac 上,如果启用 PPC/PPC64 支持,则每行最多可以收到 4 个警告。 ;)

编辑:马修在接受的答案中找到了正确的答案。

【讨论】:

    【解决方案3】:

    看起来您正在为 iOS 进行编译。代码被多次编译用于多种架构。正在为每个架构生成警告。

    【讨论】:

    • 多架构的解释是有道理的,但不确定这里的情况。如果我添加例如-arch x86_64 到我的 gcc 或 clang 标志,我仍然收到重复的警告。如果我添加-arch x86_64 -arch i386,我会收到四个警告。 :)
    • -1:显然他没有为 iOS 编译,也没有进行多架构构建。编译器调用在问题中指定。
    猜你喜欢
    • 2020-07-30
    • 2013-06-22
    • 2013-06-22
    • 1970-01-01
    • 2017-02-27
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多