Вопрос по c, gcc, mingw – MinGW GCC: «Неизвестный символ типа преобразования« h »» (snprintf)
Хорошо, у меня возникла странная проблема при компиляции 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 в виде шестнадцатеричных значений.)
printf()
иsnprintf()
- какой дистрибутив MinGW вы используете? В настоящее время я использую дистрибутив TDM.
Michael Burr
что 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 будет использовать представление по умолчанию о том, что такое поддержка формата).
44
Error: User Rate Limit Exceededsnprintf
Error: User Rate Limit ExceededFA
Error: User Rate Limit Exceeded
Socob
вот еще немного информации о проверках формата 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 - usesprintf
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