如何在mingw-w64 gcc 7.1中无需警告地打印size_t?

Sco*_*ter 16 c printf size-t

我在nuwen.net上使用minGW的mingw-w64(x64)分支.这是来自7.1版本的gcc:

gcc --version
gcc (GCC) 7.1.0
Run Code Online (Sandbox Code Playgroud)

我正在编译这个程序:

#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);
}
Run Code Online (Sandbox Code Playgroud)

有警告和c11标准:

gcc -Wall -Wextra -Wpedantic -std=c11 test_size_t.c
Run Code Online (Sandbox Code Playgroud)

我收到这些警告:

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

我想在没有警告的情况下printf一个size_t但在这种情况下不知道正确的格式说明符.

小智 21

问题不是编译器而是C库.MinGW使用Microsoft的"Visual C Runtime"(msvcrt),它只符合,不支持z格式说明符.

以下是size_t使用MinGW时可以安全打印的内容:

#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);
}
Run Code Online (Sandbox Code Playgroud)

在win64上,您将收到此代码的警告,因为PRIu64扩展为msvcrt特定I64u格式说明符.但是你可以用GCC标志来消除这个警告-Wno-pedantic-ms-format.


请注意,您需要一个类似的技巧long long(这里使用PRIu6432位和64位窗口)因为msvcrt不知道ll.


编辑:正如@MM在评论中指出的那样,您可以改为将MinGW提供的stdio支持C11的替代函数链接起来#define __USE_MINGW_ANSI_STDIO 1.如果我可以解决特殊问题msvcrt,我宁愿不链接额外的代码,但这当然是品味的问题.

  • Visual Studio 2013及更高版本支持`%zu`.用`_MSC_VER> = 1800`检查它.你声称MSVC不支持`ll`是*完全*false; 那些支持已经存在*许多*版本,所以很多我不记得什么时候它不受支持. (3认同)
  • 我刚刚检查过的@CodyGray:Windows 10系统上的msvcrt.dll版本7.0.10586.0不支持`%zu`。所以我想MSVC做类似MinGW和__USE_MINGW_ANSI_STDIO的事情,并链接一些额外的代码来支持它吗? (2认同)
  • 好吧,不,区别在于MSVC已有20年没有链接到`msvcrt.dll`了。使用的最后一个版本是VC ++6。我确实记得知道这一点,但是我以某种方式忘记了MinGW链接到Microsoft的私有运行时库。我想这是使用DDK进行链接。没有记录对msvcrt.dll的更新,因为该DLL不适合公众使用。我猜想它的`printf`支持还没有扩展,因为微软没有使用它。好吧,这并不是好像有人需要*更多*不使用MinGW的理由! (2认同)

Lun*_*din 6

评论中提到的替代解决方案是在__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);
}
Run Code Online (Sandbox Code Playgroud)

这使得代码按预期编译,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=]  
Run Code Online (Sandbox Code Playgroud)

或者,您可以在命令行上定义宏 -D__USE_MINGW_ANSI_STDIO=1