提问人:Scooter 提问时间:6/6/2017 最后编辑:Scooter 更新时间:7/5/2020 访问量:7761
如何在 mingw-w64 gcc 7.1 中毫无征兆地打印size_t?
How to printf a size_t without warning in mingw-w64 gcc 7.1?
问:
我正在使用 nuwen.net 上准备的 minGW 的 mingw-w64 (x64) fork。这是来自 gcc 的 7.1 版本:
gcc --version
gcc (GCC) 7.1.0
我正在编译这个程序:
#include <stdio.h>
int main(void)
{
size_t a = 100;
printf("a=%lu\n",a);
printf("a=%llu\n",a);
printf("a=%zu\n",a);
printf("a=%I64u\n",a);
}
带警告和 C11 标准:
gcc -Wall -Wextra -Wpedantic -std=c11 test_size_t.c
我收到这些警告:
test_size_t.c: In function 'main':
test_size_t.c:6:14: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t {aka long long unsigned int}' [-Wformat=]
printf("a=%lu\n",a);
~~^
%I64u
test_size_t.c:6:14: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t {aka long long unsigned int}' [-Wformat=]
printf("a=%lu\n",a);
~~^
%I64u
test_size_t.c:7:14: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("a=%llu\n",a);
^
test_size_t.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%llu\n",a);
^~~~~~~~~~
test_size_t.c:7:14: warning: unknown conversion type character 'l' in format [-Wformat=]
printf("a=%llu\n",a);
^
test_size_t.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%llu\n",a);
^~~~~~~~~~
test_size_t.c:8:13: warning: unknown conversion type character 'z' in format [-Wformat=]
printf("a=%zu\n",a);
^
test_size_t.c:8:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%zu\n",a);
^~~~~~~~~
test_size_t.c:8:13: warning: unknown conversion type character 'z' in format [-Wformat=]
printf("a=%zu\n",a);
^
test_size_t.c:8:9: warning: too many arguments for format [-Wformat-extra-args]
printf("a=%zu\n",a);
^~~~~~~~~
test_size_t.c:9:9: warning: ISO C does not support the 'I64' ms_printf length modifier [-Wformat=]
printf("a=%I64u\n",a);
^~~~~~~~~~~
test_size_t.c:9:9: warning: ISO C does not support the 'I64' ms_printf length modifier [-Wformat=]
我想在没有警告的情况下打印size_t,但在这种情况下不知道正确的格式说明符。
答:
问题不在于编译器,而在于 C 库。MinGW使用Microsoft的“Visual C Runtime”(),它只符合c89,不支持格式说明符。msvcrt
z
以下是使用 MinGW 时可以安全打印的方法:size_t
#include <inttypes.h>
#include <stdio.h>
#ifdef _WIN32
# ifdef _WIN64
# define PRI_SIZET PRIu64
# else
# define PRI_SIZET PRIu32
# endif
#else
# define PRI_SIZET "zu"
#endif
int main(void)
{
size_t mySize = 24;
printf("%" PRI_SIZET "\n", mySize);
}
在 win64 上,您将收到此代码的警告,因为扩展为特定于 -的格式说明符。但是你可以用 GCC 标志 .PRIu64
msvcrt
I64u
-Wno-pedantic-ms-format
请注意,您需要类似的技巧(此处在 32 位和 64 位窗口上使用),因为两者都不知道。long long
PRIu64
msvcrt
ll
编辑:正如@M.M在评论中指出的那样,您可以将MinGW提供的支持C11的替代函数与.如果我能绕过 的特殊性,我宁愿不链接额外的代码,但这当然是一个品味问题。stdio
#define __USE_MINGW_ANSI_STDIO 1
msvcrt
评论
%zu
在 Visual Studio 2013 及更高版本上受支持。使用 检查它。你声称 MSVC 不支持是完全错误的;这种支持已经存在了很多版本,很多我不记得什么时候不支持它。_MSC_VER >= 1800
ll
%zu
msvcrt.dll
__USE_MINGW_ANSI_STDIO
msvcrt.dll
msvcrt.dll
printf
msvcrt
#pragma
注释中提到的替代解决方案是抛入编译器开关:__USE_MINGW_ANSI_STDIO
#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
int main(void)
{
size_t a = 100;
printf("a=%lu\n",a);
printf("a=%llu\n",a);
printf("a=%zu\n",a);
printf("a=%I64u\n",a);
}
这使得代码按预期编译,并且 gcc 现在给出相应的警告:
warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'size_t' [-Wformat=]
warning: ISO C does not support the 'I' printf flag [-Wformat=]
warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'size_t' [-Wformat=]
或者,您可以使用以下命令在命令行上定义宏-D__USE_MINGW_ANSI_STDIO=1
评论
PRIuPTR
trick works(size_t?类型变量的跨平台格式字符串):
#include <stdio.h>
#include <inttypes.h>
int main()
{
size_t a = (size_t)(1024ULL * 1024 * 1024 * 1024 + 13);
printf("a = %" PRIuPTR "\n", a);
printf("sizeof(size_t) = %" PRIuPTR "\n", sizeof(size_t));
printf("sizeof(uintptr_t) = %" PRIuPTR "\n", sizeof(uintptr_t));
return 0;
}
输出 x86:
a = 13
sizeof(size_t) = 4
sizeof(uintptr_t) = 4
输出 x64:
a = 1099511627789
sizeof(size_t) = 8
sizeof(uintptr_t) = 8
评论
zu
是 C99 的添加,而且是正确的方法。确保编译为 C99(或更高版本)。-std=c11
msvcrt
z
#ifdef _WIN32
%I64u
msvcrt
#define __USE_MINGW_ANSI_STDIO 1