Okay, I've run into a strange issue compiling a C file with MinGW (GCC 4.6.2) on Windows 7. The file in question contains the following C code:
#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;
}
The compilation turns out like this:
$ 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]
Now, what's strange to me is that it complains about the snprintf
call on line 6, but not the printf
call on line 4. Am I missing something or is the warning just incorrect? Also, is there perhaps a better equivalent for the format string "%2hhX"
? (I'm trying to print char variables as hexadecimal values.)
Historically, MinGW has been in a bit of an odd situation, especially as far as C99 support goes. MinGW relies mostly on the msvcrt.dll runtime that's distributed with Windows, and that runtime doesn't support C99.
So with older versions of MinGW, you can run into problems in C99 mode when using C99-specific format specifiers. Also historically, GCC didn't make any special accommodations for msvcrt.dll's lack of support for C99 specifiers. So you'd get into situations where
-Wformat
wouldn't warn about a format that wouldn't work.Things are improving on both sides - GCC has specific support for -Wformat when used with the MS runtime, such as:
-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)ms_printf
option to__attribute__((__format__))
On the other side, MinGW has provided its own
snprintf()
for a while, since MSVC's variant,_snprintf()
, behaves quite differently. However, MinGW relied for a long while on theprintf()
in msvcrt.dll, so C99 format specifiers forprintf()
didn't work. At some point MinGW started providing it's own version ofprintf()
and friends so that you could get proper C99 (and GNU?) support. However, it seems that to be on the conservative side, these didn't replace the msvcrt.dll versions initially. They have names like__mingw_printf()
.It looks like at some point between 4.6.1 and 4.7.0, the MinGW headers started using the MinGW supplied versions as replacements for the msvcrt.dll function (at least if you've specifed C99).
However, it seems that with the newer versions, GCC and MinGW are still a little out of sync. Where as before GCC would not warn about specifiers that wouldn't actually work on MinGW, not it complains about spcifiers that will.
You may want to try the following snipet of code to see how well your version of MinGW support
"hhX"
:I'm not sure what to suggest to fix the problem you're running into - I think that you may be able to patch the MinGW
stdio.h
header so that it has a__attribute__((__format__ (gnu_printf, ...)))
attribute on the printf functions (they're not there in the newerstdio.h
, so GCC will use it's default idea of what the format support is).In addition to the other answer, here is some more info on printf format checks in GCC:
When you say
__attribute__((__format__ (FORMAT, ...)))
, the value ofFORMAT
can be (as far as printf is concerned) one of the following:printf
,gnu_printf
,ms_printf
.ms_printf
makes GCC assume that function takes a format string intended for Microsoft Visual Studio CRT printf family functions. It means that GCC will complain aboutz
,hh
andll
, but will passI64
without warning.gnu_printf
makes GCC assume GNU libc printf implementation underneath (or maybe just a POSIX/C99-compliant printf implementation, i'm not sure). Therefore GCC will complain aboutI64
and other Microsoft extensions, but will acceptz
,hh
andll
.printf
is an alias forms_printf
when compiling for Windows, and an alias forgnu_printf
otherwise.Note that this check is completely orthogonal to the actual printf implementation being used. This is easy to see if you write your own printf-like function and put
__attribute__((__format__ (FORMAT, ...)))
on it - GCC will complain about different things depending onFORMAT
, but you can do whatever you want inside the function.Available printf implementations that i know of:
-D__USE_MINGW_ANSI_STDIO=1
) in MinGW.org and MinGW-w64 toolchains. Complies withms_printf
(fully?) andgnu_printf
format (partially - does not support positional arguments).-D__USE_MINGW_ANSI_STDIO=1
). Complies withms_printf
(duh...), compliance withgnu_printf
is very low and depends on runtime version (old versions did not supportll
, new ones do;z
andhh
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).ms_printf
andgnu_printf
completely (or near-completely).The
stdio.h
header in MinGW.org does not useattribute format
.The
stdio.h
header in MinGW-w64 usesattribute format gnu_printf
for MinGW ANSI STDIO implementation, but does not use anything for MSVCRT implementation. FIXED: In newer versions of MinGW-w64 headersstdio.h
will useattribute format ms_printf
for MSVCRT implementation.gnulib is fully aware of the difference between
printf
andgnu_printf
, and will pick one or the other depending on some complicated macros (presumably, accompanying it with a proper implementation that supports what the format says it does).Pieces of software that are known (at the moment) to have problems with GCC format checks:
printf
format, but implementation is from gnulib; there's an outstanding bug for changing it tognu_printf
z
formats, but official binaries are built against MSVCRT; it also usesprintf
format in its extension headers, even though extensions often usez
as well