web-dev-qa-db-fra.com

Comment imprimer un size_t sans prévenir dans mingw-w64 gcc 7.1?

J'utilise la fourche mingw-w64 (x64) de minGW telle que préparée sur nuwen.net. Cela provient de la version 7.1 de gcc:

gcc --version
gcc (GCC) 7.1.0

Je compile ce programme:

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

avec avertissements et norme c11:

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

et je reçois ces avertissements:

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

Je voudrais imprimer un size_t sans avertissement, mais je ne connais pas le spécificateur de format correct dans cette situation.

14
Scooter

Le problème n'est pas le compilateur mais la bibliothèque C. MinGW utilise le "Visual C Runtime" de Microsoft (msvcrt) qui est uniquement conforme à c89 et ne prend pas en charge le spécificateur de format z.

Voici ce que vous pouvez faire pour imprimer un size_t en toute sécurité avec 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);
}

Sur win64, vous recevez un avertissement avec ce code, car PRIu64 se développe en spécificateur de format msvcrt-spécifique I64u. Mais vous pouvez désactiver cet avertissement avec l'indicateur GCC -Wno-pedantic-ms-format.


Notez que vous avez besoin d'une astuce similaire pour long long (ici, en utilisant PRIu64 sur les fenêtres 32 bits et 64 bits), car msvcrt ne sait pas ll non plus.


edit : comme l'a souligné @ M.M dans un commentaire, vous pouvez lier à la place des fonctions alternatives stdio fournies par MinGW qui prennent en charge C11 avec #define __USE_MINGW_ANSI_STDIO 1. Je préfère ne pas lier de code supplémentaire si je peux contourner les particularités de msvcrt, mais c'est bien sûr une question de goût.

18
user2371524

La solution alternative mentionnée dans les commentaires consiste à lancer dans le commutateur de compilation __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);
}

Cela rend le code compilé comme prévu et gcc donne maintenant les avertissements appropriés: 

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