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

发布于 2024-12-04 04:54:51 字数 3010 浏览 2 评论 0原文

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

I'm curious why GCC shows me two identical warnings when compiling this file:

$ 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’

Interestingly, Clang also gives two warnings:

$ 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.

Any ideas?


For info:

$ 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

EDIT: the 'multi-architecture' hypothesis a few have suggested sounded good, but I'm not sure it's right. If I force a single architecture with -arch, I get two warnings. If I specify -arch x86_64 -arch i386, I get two sets of duplicate warnings!

$ 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’

EDIT: I don't get dupes for all warning types. -Wformat is the only one I've come across so far. For example, if I throw in an unused variable I only get one warning for that:

$ 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’

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

左秋 2024-12-11 04:54:51

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

(例如,参见 printf() 的声明 此处 以及 __printflike()此处

...但是 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;
}

This is because Apple's stdio.h header attaches a GCC format attribute to its declaration of printf()...

(e.g. see the declaration of printf() here and the declaration of the __printflike() macro here)

...but GCC (and Clang, due to it trying to be very GCC-compatible!) already has built-in knowledge that printf() is a function which takes printf-style arguments. You're getting one warning due to the built-in knowledge, and a second warning due to the explicit attribute.

You can demonstrate the same behaviour on other platforms (with at least several versions of GCC) by doing the same thing yourself:

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;
}
烟织青萝梦 2024-12-11 04:54:51

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

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

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

If you're targetting two CPU architectures (ARMv6/ARMv7 on iOS, for instance, or i386/x86_64 on Mac), you'll see two copies of each warning because the compiler runs twice for each file (once for each architecture.)

On a Mac, you can get it up to 4 warnings per line if you enable PPC/PPC64 support. ;)

Edit: Matthew's got it spot-on in the accepted answer.

栖迟 2024-12-11 04:54:51

看起来您正在为 iOS 进行编译。该代码针对多种架构进行了多次编译。正在为每个架构生成警告。

It looks like you're compiling for iOS. The code is being compiled multiple times for multiple architectures. The warning is being generating for each architecture.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文