MinGW GCC:"未知的转换类型字符'h'"(snprintf)

Soc*_*cob 14 c printf gcc mingw

好吧,我遇到了一个奇怪的问题,在Windows 7上使用MinGW(GCC 4.6.2)编译C文件.该文件包含以下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;
}
Run Code Online (Sandbox Code Playgroud)

编译结果如下:

$ 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]
Run Code Online (Sandbox Code Playgroud)

现在,对我来说很奇怪的是,它抱怨snprintf第6行的电话,而不是第printf4行的电话.我错过了什么或警告是不正确的?另外,格式字符串可能有更好的等价物"%2hhX"吗?(我正在尝试将char变量打印为十六进制值.)

Mic*_*urr 20

从历史上看,MinGW在一些奇怪的情况下,特别是在C99支持下.MinGW主要依赖于随Windows一起发布的msvcrt.dll运行时,并且该运行时不支持C99.

因此,对于旧版本的MinGW,使用C99特定的格式说明符时,可能会在C99模式下遇到问题.同样在历史上,GCC没有为msvcrt.dll缺乏对C99说明符的支持做任何特殊的调整.因此,您将遇到-Wformat无法警告无法使用的格式的情况.

双方都在改进 - GCC在与MS运行时一起使用时特别支持-Wformat,例如:

  • -Wpedantic-ms-format所以海湾合作委员会不会抱怨"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上工作的说明者,而不是它会抱怨那些会产生spcifiers的.

您可能需要尝试以下snipet代码来查看您的MinGW版本支持的程度"hhX":

printf("%hhX\n", 0x11223344);
__mingw_printf("%hhX\n", 0x11223344);
Run Code Online (Sandbox Code Playgroud)

我不确定要解决你遇到的问题是什么建议 - 我认为你可以修补MinGW stdio.h标题,使它__attribute__((__format__ (gnu_printf, ...)))在printf函数上有一个属性(它们不在新的stdio.h,所以GCC将使用它的格式支持的默认概念).