web-dev-qa-db-ja.com

mingw-w64 gcc 7.1で警告なしにsize_tをprintfする方法は?

Nuwen.netで準備されているminGWのmingw-w64(x64)フォークを使用しています。これは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をprintfしたいのですが、この状況での正しいフォーマット指定子がわかりません。

16
Scooter

問題はコンパイラではなく、Cライブラリです。 MinGWは、Microsoftの「VisualCランタイム」(msvcrt)を使用します。これは、 c89 にのみ準拠し、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では、PRIu64msvcrt固有のI64u形式指定子に展開されるため、このコードで警告が表示されます。ただし、GCCフラグ-Wno-pedantic-ms-formatを使用してこの警告を消音することができます。


msvcrtllを知らないため、long long(ここでは32ビットウィンドウと64ビットウィンドウの両方でPRIu64を使用)にも同様のトリックが必要であることに注意してください。


edit:@ MMがコメントで指摘しているように、代わりにMinGWが提供するC11をサポートする代替のstdio関数を#define __USE_MINGW_ANSI_STDIO 1にリンクできます。 。 msvcrtの特性を回避できるのであれば、余分なコードをリンクしたくないのですが、それはもちろん好みの問題です。

22
user2371524

コメントに記載されている代替ソリューションは、__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を使用してマクロを定義することもできます。

2
Lundin