Почему GCC выдает двойные предупреждения о неверном спецификаторе формата printf? - PullRequest
7 голосов
/ 12 сентября 2011

Мне любопытно, почему 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 ]

8 голосов
/ 13 сентября 2011

Это связано с тем, что заголовок 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;
}
3 голосов
/ 12 сентября 2011

Если вы нацелены на две архитектуры ЦП (например, ARMv6 / ARMv7 на iOS или i386 / x86_64 на Mac), вы увидите две копии каждого предупреждения, потому что компилятор запускается дважды для каждого файла (по одному для каждогоархитектура.)

На Mac вы можете получить до 4 предупреждений на строку, если включите поддержку PPC / PPC64.;)

Редактировать : Мэттью сразу понял в принятом ответе.

2 голосов
/ 12 сентября 2011

Похоже, вы компилируете для iOS. Код компилируется несколько раз для нескольких архитектур. Предупреждение генерируется для каждой архитектуры.

...