format de chaîne pour intptr_t et uintptr_t

Quel est le format de chaîne pour intptr_t et uintptr_t qui est valide pour les architectures 32 et 64 bits.

MODIFIER

 warning: format '%x' expects type 'unsigned int', but argument 2 has type "AAA" 

C’est l’avertissement que je reçois en 64 bits, mais pas en 32 bits.

  intptr_t AAA 

Ce serait les macros suivantes de inttypes.h :

Pour printf : PRIdPTR PRIiPTR PRIoPTR PRIuPTR PRIxPTR PRIXPTR

Pour scanf : SCNdPTR SCNiPTR SCNoPTR SCNuPTR SCNxPTR

Exemple d’utilisation:

 uinptr_t p = SOME_VALUE; printf("Here's a pointer for you: %" PRIxPTR "\n", p); 

Je pense que même long int est dangereux, et vous devriez essayer long long int , ce qui doit exister parce que vous travaillez sur une architecture 64 bits et que vous avez déjà intptr_t .

Sur certaines architectures 64 bits (je pense que Microsoft Windows le serait), un long int peut être conservé dans une largeur de 32 bits, afin de satisfaire à l’hypothèse MS-DOS-age selon laquelle short int est toujours 16 bits et long int est toujours 32 -bit.

Même sur les plates-formes avec long int sur 32 bits, printf("%llx", (unsigned long long)AAA); travaillerait. Et vous devriez envisager une forme plus préférable printf("%jx", (uintmax_t)AAA); si possible.

Notez que pour certains anciens compilateurs, vous devrez peut-être utiliser "%Lx" (pour GNU C, avec la conversion vers unsigned long long ) ou "%I64x" (pour Visual C ++, avec la __uint64 vers __uint64 ) pour les entiers 64 bits.

PS %p peut ne pas être bon dans ce cas, car %p peut imprimer le mot nu 0x avant les hexadécimaux et / ou peut imprimer une valeur remplie de zéros. Si les deux sont appliqués, par exemple, le code printf("%p\n", (void*)16); imprimera 0x00000010 sur les plates-formes 32 bits et 0x0000000000000010 sur les plates-formes 64 bits; l’affiche aurait dû espérer que 10 seulement soient imprimées.

Je pense que vous devriez envisager d’utiliser le modificateur ‘z’. Cela convertira tout ce qui correspond à une taille_t og ssize_t, et j’ai constaté que cela fonctionne également avec (u) intptr_t.

Par exemple:

intptr_t ip = …; printf (“ip =% zd \ n”, ip);

%p devrait remplacer %x , car uintptr_t est défini comme un entier non signé de la même taille qu’un pointeur sur la plate-forme.

EDIT: Malheureusement, au moins sur mon compilateur, vous devez convertir la variable en (void *). Cependant, je pense qu’il est prudent de convertir uintptr_t en pointeur.

Je comstack du code dans un environnement pour lequel, pour une raison PRI.PTR macros PRI.PTR ne sont pas définies dans inttypes.h , et dans lequel intptr_t est défini comme int en 32 bits et long int en 64 bits.

J’ai corrigé les avertissements en utilisant un spécificateur de format %li et en convertissant les variables en long int dans les parameters printf . Ceci est sûr dans cet environnement car un intptr_t ne peut jamais être plus long int qu’un long int , comme décrit ci-dessus.

Je ne recommanderais pas d’utiliser cette solution si vous pouvez l’éviter, mais cela résout au moins les avertissements.

 ####################################### CPP type proving code (identifying type by typeid) $ cat typeid.cpp #include  #include  #include  #include  #include  #define name(t) printf("%30s : %s\n", #t, typeid(t).name()) // g++|clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe // g++|clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe int main(int argc, char* argv[]) { name(ptrdiff_t); name(intptr_t); name(uintptr_t); return 0; } ####################################### C type proving code (identifying type by _Generic) $ cat typeid.c #include  #include  #include  #include  /* matches the type name of an expression */ #define name_match(e) _Generic((e), \ _Bool: "_Bool", \ char: "char", \ signed char: "signed char", \ unsigned char: "unsigned char", \ short: "short", \ unsigned short: "unsigned short", \ int: "int", \ unsigned int: "unsigned int", \ long: "long", \ unsigned long: "unsigned long", \ long long: "long long", \ unsigned long long: "unsigned long long", \ float: "float", \ double: "double", \ long double: "long double", \ default: "unknown") #define name(t, e) printf("%30s : %s\n", #t, name_match(e)) int main() { ptrdiff_t ptrdiff_v = 0; intptr_t intptr_v = 0; uintptr_t uintptr_v = 0; name(ptrdiff_t, ptrdiff_v); name(intptr_t, intptr_v); name(uintptr_t, uintptr_v); } ####################################### run in arch32 $ clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe ptrdiff_t : i intptr_t : i uintptr_t : j $ clang -o ./typeid.exe typeid.c -m32 && ./typeid.exe ptrdiff_t : int intptr_t : int uintptr_t : unsigned int result: intptr_t == ptrdiff_t uintptr_t == unsigned ptrdiff_t ####################################### run in arch64 $ clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe ptrdiff_t : l intptr_t : l uintptr_t : m $ clang -o ./typeid.exe typeid.c -m64 && ./typeid.exe ptrdiff_t : long intptr_t : long uintptr_t : unsigned long result: intptr_t == ptrdiff_t uintptr_t == unsigned ptrdiff_t ####################################### man 3 printf t -- A following integer conversion corresponds to a ptrdiff_t argument. ####################################### conclusion // intptr_t == ptrdiff_t // uintptr_t == unsigned ptrdiff_t // so: // 1) intptr_t has ssortingng format %td // 2) uintptr_t has ssortingng format %tu #include  #include  int main(int argc, char *argv[]) { intptr_t x = 0; uintptr_t y = 0; scanf("%td %tu", &x, &y); printf("out: %td %tu\n", x, y); return 0; }