web-dev-qa-db-de.com

Wie drucke ich ein size_t ohne Vorwarnung in mingw-w64 gcc 7.1?

Ich benutze die auf nuwen.net vorbereitete Gabel mingw-w64 (x64) von minGW. Dies ist aus der 7.1-Version von gcc:

gcc --version
gcc (GCC) 7.1.0

Ich kompiliere dieses Programm:

#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);
}

mit warnungen und c11 standard:

gcc -Wall -Wextra -Wpedantic -std=c11 test_size_t.c

und ich bekomme diese Warnungen:

   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=]

Ich möchte ein size_t ohne Vorwarnung ausdrucken, kenne aber in dieser Situation nicht den korrekten Formatbezeichner.

14
Scooter

Das Problem ist nicht der Compiler, sondern die C-Bibliothek. MinGW verwendet die "Visual C Runtime" von Microsoft (msvcrt), die nur mit c89 konform ist, und unterstützt den Formatbezeichner z nicht.

So können Sie einen size_t bei Verwendung von MinGW sicher drucken:

#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);
}

Unter win64 würden Sie mit diesem Code eine Warnung erhalten, da PRIu64 zum msvcrt-spezifischen I64u-Formatbezeichner erweitert wird. Sie können diese Warnung jedoch mit dem GCC-Flag -Wno-pedantic-ms-format abstellen.


Beachten Sie, dass Sie einen ähnlichen Trick für long long benötigen (hier verwenden Sie PRIu64 in 32-Bit- und 64-Bit-Fenstern), da msvcrtll ebenfalls nicht kennt.


edit : Wie von @M.M in einem Kommentar ausgeführt, können Sie stattdessen die von MinGW bereitgestellten alternativen stdio-Funktionen, die C11 unterstützen, mit #define __USE_MINGW_ANSI_STDIO 1 verknüpfen. Ich ziehe es vor, keinen zusätzlichen Code zu verknüpfen, wenn ich die Besonderheiten von msvcrt umgehen kann, aber das ist natürlich Geschmackssache.

18
user2371524

Die in den Kommentaren erwähnte alternative Lösung besteht darin, den Compiler-Schalter __USE_MINGW_ANSI_STDIO zu werfen:

#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);
}

Dadurch wird der Code wie erwartet kompiliert, und gcc gibt jetzt die entsprechenden Warnungen aus: 

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=]  
0
Lundin