Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does GCC show duplicate warnings for bad printf format specifier?

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’
like image 532
Simon Whitaker Avatar asked Sep 11 '11 20:09

Simon Whitaker


2 Answers

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;
}
like image 168
Matthew Slattery Avatar answered Nov 19 '22 17:11

Matthew Slattery


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.

like image 40
Jonathan Grynspan Avatar answered Nov 19 '22 15:11

Jonathan Grynspan