2012-05-20 6 views
10

Хорошо, у меня возникла странная проблема с компиляцией файла C с помощью MinGW (GCC 4.6.2) в Windows 7. Этот файл содержит следующий код C:MinGW GCC: «Неизвестный тип символа преобразования« h »(snprintf)

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    printf("%2hhX\n", 250); 
    char c[80]; 
    snprintf(c, sizeof(c), "%2hhX", 250); 
    printf("%s\n", c); 
    return 0; 
} 

компиляция получается, как это:

$ gcc.exe -std=c99 -pedantic -Wall test.c 
test.c: In function 'main': 
test.c:6:2: warning: unknown conversion type character 'h' in format [-Wformat] 
test.c:6:2: warning: too many arguments for format [-Wformat-extra-args] 

Теперь, что странно для меня является то, что он жалуется на snprintf вызова на линии 6, но не в printf вызова на линии 4. Я что-то пропустил или это предупреждение просто неверно? Кроме того, может быть, лучший эквивалент для строки формата "%2hhX"? (Я пытаюсь напечатать переменные char как шестнадцатеричные значения.)

+0

Интересно, что прекрасно работает с GCC 4.3.4: http://ideone.com/LAPP9. Я также пробовал с 4.1.2, и все в порядке. –

+0

Использование MinGW GCC 4.6.1 Я получаю предупреждения как на 'printf()', так и на 'snprintf()' - какой дистрибутив MinGW вы используете? В настоящее время я использую дистрибутив TDM. –

+0

@MichaelBurr: Я даже не понял, что было несколько дистрибутивов MinGW. Я использую «стандартный» вариант, я думаю ([mingw.org] (http://www.mingw.org/), установленный с https://sourceforge.net/projects/mingw/files/Installer/mingw -get-инст /). Значит, это изменит ситуацию? – Socob

ответ

17

Исторически сложилось так, что MinGW был в некоторой степени странной, особенно в том, что касается поддержки C99. MinGW полагается в основном на среду исполнения msvcrt.dll, которая распространяется вместе с Windows, и эта среда выполнения не поддерживает C99.

Таким образом, с более старыми версиями MinGW вы можете столкнуться с проблемами в режиме C99 при использовании спецификаторов формата C99. Также исторически GCC не создавал особых условий для отсутствия поддержки msvcrt.dll спецификаторов C99. Таким образом, вы попадаете в ситуации, когда -Wformat не будет предупреждать о формате, который бы не работал.

вещи улучшаются с обеих сторон - GCC имеет определенную поддержку -Wformat при использовании с MS выполнения, например:

  • -Wpedantic-ms-format так, что GCC не будет сетовать "I32" и "I64" (хотя это документирована, я все еще получаю жалобы о том, что будучи непризнанным даже в 4.7.0 - может быть, это совершенно новый)
  • ms_printf вариант __attribute__((__format__))

на другая сторона, MinGW предоставила свое собственное snprintf() некоторое время, так как вариант MSVC, _snprintf(), ведет себя совершенно по-другому. Тем не менее, MinGW долгое время полагался на printf() в msvcrt.dll, поэтому спецификаторы формата C99 для printf() не работали. В какой-то момент MinGW начал предоставлять свою собственную версию printf() и друзьям, чтобы вы могли получить правильную поддержку C99 (и GNU?). Тем не менее, похоже, что с консервативной стороны они не заменяли версии msvcrt.dll изначально. У них есть имена, такие как __mingw_printf().

Похоже, что в некоторый момент между 4.6.1 и 4.7.0 заголовки MinGW начали использовать поставляемые версии MinGW в качестве замены для функции msvcrt.dll (по крайней мере, если вы указали C99).

Однако, похоже, что с более новыми версиями GCC и MinGW все еще немного не синхронизированы. Где, как и раньше, GCC не будет предупреждать о спецификаторах, которые на самом деле не работали бы на MinGW, но не жалуются на то, что это будет делать.

Вы можете попробовать следующий snipet кода, чтобы увидеть, насколько хорошо ваш вариант поддержки MinGW "hhX":

printf("%hhX\n", 0x11223344); 
__mingw_printf("%hhX\n", 0x11223344); 

Я не уверен, что предложить, чтобы решить эту проблему вы работаете в - Я думаю, что вы можете исправить заголовок MinGW stdio.h, чтобы он имел атрибут __attribute__((__format__ (gnu_printf, ...))) для функций printf (их нет в новее stdio.h, поэтому GCC будет использовать идею по умолчанию для поддержки формата).

+0

Ваш фрагмент кода не дает никаких предупреждений, когда я компилирую его с опциями сверху и дважды печатаю '44', как и следовало ожидать; кажется, что только «snprintf», в частности, зависит от предупреждения при моей установке. Тем не менее, код, который я написал выше, печатает 'FA' дважды, поэтому функция работает правильно. Итак, по сути, предупреждение действительно неверно, и это просто причуда с MinGW и GCC? Если это так, это все, что мне действительно нужно знать - я просто хотел выяснить, пропустил ли я что-то в коде или мог ли я игнорировать предупреждение. – Socob

+0

Спасибо. Даже на MinGW 4.9.1 '__mingw_printf' - это тот, который работает для меня без предупреждений. Покроет его в макрос для общности. – legends2k

3

В дополнении к другому ответу, вот еще некоторая информация о проверках формата Printf в НКУ:

Когда вы говорите __attribute__((__format__ (FORMAT, ...))), значение FORMAT может быть (насколько Printf обеспокоен) один из следующих : printf, gnu_printf, ms_printf.

ms_printf GCC предполагает, что функция принимает строку формата, предназначенную для семейств семейства Microsoft Visual Studio CRT printf. Это означает, что GCC будет жаловаться на z, hh и ll, но пройдет I64 без предупреждения.

gnu_printf делает GCC предполагаемой реализацией GNU libc printf (или, может быть, просто совместимой с POSIX/C99 функцией printf, я не уверен). Поэтому GCC будет жаловаться на I64 и другие расширения Microsoft, но примет z, hh и ll.

printf - это псевдоним для ms_printf при компиляции для Windows и псевдоним для gnu_printf.

Обратите внимание, что эта проверка полностью ортогональна используемой реализации printf. Это легко увидеть, если вы напишете свою собственную функцию, подобную printf, и положите на нее __attribute__((__format__ (FORMAT, ...))) - GCC будет жаловаться на разные вещи в зависимости от FORMAT, но вы можете делать все, что хотите внутри функции.

Доступные PRINTF реализации, которые я знаю:

  • MinGW ANSI STDIO (компилировать с -D__USE_MINGW_ANSI_STDIO=1) в MinGW.org и MinGW-w64. Компилированные инструменты Соответствует ms_printf (полностью?) И gnu_printf (частично - не поддерживает позиционные аргументы).
  • MSVCRT (скомпилируйте без -D__USE_MINGW_ANSI_STDIO=1). Соответствует ms_printf (duh ...), соответствие gnu_printf очень мало и зависит от версии исполнения (старые версии не поддерживали ll, новые - z и hh пока не поддерживаются ни в одной версии, GCC блаженно не знает о эти разработки, хотя и предполагают худший случай, msvcrt от эпохи VC 6.0, похоже).
  • gnulib. Соответствует ms_printf и gnu_printf полностью (или почти полностью).

Заголовок stdio.h в MinGW.org не использует attribute format.

В заголовке stdio.h в MinGW-w64 используется attribute format gnu_printf для реализации MinGW ANSI STDIO, но ничего не используется для реализации MSVCRT. FIXED: В новых версиях заголовков MinGW-w64 stdio.h будет использовать attribute format ms_printf для реализации MSVCRT.

gnulib полностью осознает разницу между printf и gnu_printf и будет выбирать тот или иной в зависимости от некоторых сложных макросов (предположительно, сопровождающих его с правильной реализацией, которая поддерживает то, что говорит формат).

Кусочки программного обеспечения, которые известны (в данный момент), чтобы иметь проблемы с проверками в формате GCC:

  • бойкие - использует формат printf, но реализация от gnulib; есть замечательная ошибка для ее изменения до gnu_printf
  • CPython - код полный z форматов, но официальные двоичные файлы создаются на основе MSVCRT; он также использует формат printf в своих заголовках расширения, хотя расширения часто используют z, а
Смежные вопросы