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したいのですが、この状況での正しいフォーマット指定子がわかりません。
問題はコンパイラではなく、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では、PRIu64
がmsvcrt
固有のI64u
形式指定子に展開されるため、このコードで警告が表示されます。ただし、GCCフラグ-Wno-pedantic-ms-format
を使用してこの警告を消音することができます。
msvcrt
もll
を知らないため、long long
(ここでは32ビットウィンドウと64ビットウィンドウの両方でPRIu64
を使用)にも同様のトリックが必要であることに注意してください。
edit:@ MMがコメントで指摘しているように、代わりにMinGWが提供するC11をサポートする代替のstdio
関数を#define __USE_MINGW_ANSI_STDIO 1
にリンクできます。 。 msvcrt
の特性を回避できるのであれば、余分なコードをリンクしたくないのですが、それはもちろん好みの問題です。
コメントに記載されている代替ソリューションは、__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
を使用してマクロを定義することもできます。