如何在 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) 分支。这是来自 7.1 版本的 gcc :

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使用微软的"Visual C Runtime"(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 上,您会收到此代码的警告,因为 PRIu64 扩展为 msvcrt 特定的 I64u 格式说明符。但是您可以使用 GCC 标志 -Wno-pedantic-ms-format.

消除此警告

请注意,您需要对 long long 使用类似的技巧(此处在 32 位和 64 位 windows 上使用 PRIu64),因为 msvcrt 不知道 ll 要么。


编辑:正如@M.M在评论中指出的,您可以改为link MinGW提供的替代stdio函数#define __USE_MINGW_ANSI_STDIO 1 支持 C11。如果我能绕过 msvcrt 的特殊性,我不想 link 额外的代码,但这当然是个人喜好问题。

评论中提到的替代解决方案是加入 __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 技巧有效 (Cross platform format string for variables of type 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