Вопрос по c, gcc, mingw – MinGW GCC: «Неизвестный символ типа преобразования« h »» (snprintf)

12

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

#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 в виде шестнадцатеричных значений.)

Используя MinGW GCC 4.6.1, я получаю предупрежденияprintf() иsnprintf() - какой дистрибутив MinGW вы используете? В настоящее время я использую дистрибутив TDM. Michael Burr
@MichaelBurr: э-э, я даже не осознавал, что было несколько дистрибутивов MinGW. Я использую «стандарт». один, я думаю (mingw.org, установлен сsourceforge.net/projects/mingw/files/Installer/mingw-get-inst). Будет ли это иметь значение, хотя? Socob
Интересно, что он отлично работает с GCC 4.3.4:ideone.com/LAPP9, Я также пытался с 4.1.2, и это тоже хорошо. Oliver Charlesworth
Кроме того, я еще больше запутался, когда у нас есть 3 различных поведения в 4 версиях GCC. Строка форматаis правда, правда, не так ли? Socob
@Socob: я обычно использую TDM MinGW (tdm-gcc.tdragon.net) и / или nuwen 's (nuwen.net/mingw.html). Я обнаружил, что их гораздо проще установить, чем официальный MinGW (nuwen 'буквально распаковывает архив), они упаковывают дополнительные полезные библиотеки (например, pthreads-win32 в TDM и Boost в nuwen), а в TDM есть опция для 64-битного компилятора таргетинга. Michael Burr

Ваш Ответ

2   ответа
19

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

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

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

-Wpedantic-ms-format so that GCC won't complain about "I32" and "I64" (even though it's documented, I still get a complaint about it being unrecognized even in 4.7.0 - maybe it's brand new) the ms_printf option to __attribute__((__format__))

С другой стороны, MinGW предоставил свойsnprintf() некоторое время, так как вариант MSVC,_snprintf()ведет себя совсем по-другому. Однако МинГВ долгое время полагалось на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, но не будет жаловаться на spcifiers, которые будут работать.

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

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

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

Error: User Rate Limit Exceeded44Error: User Rate Limit ExceededsnprintfError: User Rate Limit ExceededFAError: User Rate Limit Exceeded Socob
Error: User Rate Limit Exceeded__mingw_printfError: User Rate Limit Exceeded
3

вот еще немного информации о проверках формата printf в GCC:

Когда ты сказал__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 (compile with -D__USE_MINGW_ANSI_STDIO=1) in MinGW.org and MinGW-w64 toolchains. Complies with ms_printf (fully?) and gnu_printf format (partially - does not support positional arguments). MSVCRT (compile without -D__USE_MINGW_ANSI_STDIO=1). Complies with ms_printf (duh...), compliance with gnu_printf is very low and depends on runtime version (old versions did not support ll, new ones do; z and hh are not supported in any version so far; GCC is blissfully unaware of these developments though, and assumes the worst case, msvcrt from VC 6.0 era, it seems). gnulib. Complies with ms_printf and gnu_printf completely (or near-completely).

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

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

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

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

glib - uses printf format, but implementation is from gnulib; there's an outstanding bug for changing it to gnu_printf CPython - the code is full of z formats, but official binaries are built against MSVCRT; it also uses printf format in its extension headers, even though extensions often use z as well

Похожие вопросы