Как печатать f size_t без предупреждения в mingw-w64 gcc 7.1?

Я использую вилку mingw-w64 (x64) minGW, подготовленную на nuwen.net. Это из версии 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 без предупреждения, но в этой ситуации не знаю правильного спецификатора формата.

Ответ 1

Проблема заключается не в компиляторе, а в библиотеке 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);
}

В win64 вы получите предупреждение с этим кодом, потому что PRIu64 расширяется до спецификатора формата msvcrt -специфического I64u. Но вы можете отключить это предупреждение флагом GCC -Wno-pedantic-ms-format.


Обратите внимание, что вам нужен подобный трюк для long long (здесь используется PRIu64 на обоих 32-битных и 64-битных окнах), потому что msvcrt не знает ll.


edit: как указано в комментарии M.MM в комментарии, вместо этого вы можете использовать альтернативные stdio функции, поддерживающие MinGW, которые поддерживают C11 с помощью #define __USE_MINGW_ANSI_STDIO 1. Я предпочитаю не связывать дополнительный код, если я могу обойти особенности msvcrt, но это, конечно, вопрос вкуса.

Ответ 2

Альтернативное решение, упомянутое в комментариях, заключается в том, чтобы включить переключатель компилятора __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=]