为什么GCC会显示错误的printf格式说明符的重复警告?

时间:2011-09-11 20:04:43

标签: c gcc compilation clang

我很好奇为什么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’

3 个答案:

答案 0 :(得分:8)

这是因为Apple的stdio.h标题在其printf()的声明中附加GCC format attribute ...

(例如,见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;
}

答案 1 :(得分:3)

如果你的目标是两个CPU架构(例如iOS上的ARMv6 / ARMv7或Mac上的i386 / x86_64),你会看到每个警告的两个副本,因为编译器为每个文件运行两次(每个文件一次)体系结构。)

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

编辑:马修在接受的答案中明白了这一点。

答案 2 :(得分:2)

看起来你正在为iOS编译。对于多种体系结构,代码正在被多次编译。正在为每个架构生成警告。