Quelle est la bonne utilisation de printf pour afficher des pointeurs avec des 0

En C, j’aimerais utiliser printf pour afficher les pointeurs, et pour qu’ils s’alignent correctement, j’aimerais les append à 0.

Je pense que la bonne façon de faire était de:

  printf ("% 016p", ptr); 

Cela fonctionne, mais ce gcc se plaint avec le message suivant:

  avertissement: indicateur '0' utilisé avec le format '% p' ​​gnu_printf 

J’ai googlé un peu pour cela, et le sujet suivant est sur le même sujet, mais ne donne pas vraiment de solution.

http://gcc.gnu.org/ml/gcc-bugs/2003-05/msg00484.html

En le lisant, il semble que la raison pour laquelle gcc se plaint est que la syntaxe que j’ai suggérée n’est pas définie dans C99. Mais je n’arrive pas à trouver une autre manière de faire la même chose d’une manière standard approuvée.

Alors voici la double question:

  • Est-ce que je comprends bien que ce comportement n’est pas défini par la norme C99?
  • Si oui, existe-t-il un moyen standard, portable, de le faire?

#include

#include

printf("%016" PRIxPTR "\n", (uintptr_t)ptr);

mais il n’imprimera pas le pointeur de la manière définie par l’implémentation (dit DEAD:BEEF pour le mode segmenté 8086).

Utilisation:

 #include  printf("0x%016" PRIXPTR "\n", (uintptr_t) pointer); 

Ou utilisez une autre variante des macros de cet en-tête.

Notez également que certaines implémentations de printf() impriment un ‘ 0x ‘ devant le pointeur; d’autres non (et les deux sont corrects selon la norme C).

Le seul moyen portable d’imprimer des valeurs de pointeur est d’utiliser le spécificateur "%p" , qui produit une sortie définie par l’implémentation. (La conversion en uintptr_t et en utilisant PRIxPTR est susceptible de fonctionner, mais (a) uintptr_t été introduit en C99, certains compilateurs peuvent ne pas le prendre en charge, et (b) il n’existe pas forcément même en C99 assez grand pour contenir toutes les valeurs de pointeur possibles.

Utilisez donc "%p" avec sprintf() (ou snprintf() , si vous en avez) pour imprimer dans une chaîne, puis imprimez le remplissage de chaîne avec des espaces en blanc.

Un problème est qu’il n’y a pas vraiment de moyen de déterminer la longueur maximale de la chaîne produite par "%p" .

Ceci est certes gênant (bien que vous puissiez bien sûr l’emballer dans une fonction). Si vous n’avez pas besoin d’une portabilité à 100%, je n’ai jamais utilisé un système qui lancait le pointeur vers unsigned long et que l’impression du résultat à l’aide de "0x%16lx" ne fonctionnerait pas. [ MISE À JOUR : Oui, j’ai. Windows 64 bits a des pointeurs 64 bits et 32 ​​bits unsigned long .] (Ou vous pouvez utiliser "0x%*lx" et calculer la largeur, probablement quelque chose comme sizeof (void*) * 2 Si vous êtes vraiment paranoïaque , vous pouvez prendre en compte les systèmes où CHAR_BIT > 8 , vous aurez donc plus de 2 chiffres hexadécimaux par octet.)

Cette réponse est similaire à celle donnée précédemment dans https://stackoverflow.com/a/1255185/1905491 mais tient également compte des largeurs possibles (comme indiqué par https://stackoverflow.com/a/6904396/1905491 que je n’a pas reconnu jusqu’à ce que ma réponse a été rendue en dessous;). Les éléments suivants seront imprimés en tant que 8 caractères hexadécimaux passés sur des machines sane * où ils peuvent être représentés par 32 bits, 16 sur 64b et 4 sur 16b.

 #include  #define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2)) printf("0x%0*" PRIxPTR, PRIxPTR_WIDTH, (uintptr_t)pointer); 

Notez l’utilisation du caractère astérisque pour extraire la largeur par l’argument suivant, qui se trouve dans C99 (probablement avant?), Mais que l’on voit rarement “dans la nature”. C’est bien mieux que d’utiliser la conversion p car cette dernière est définie par l’implémentation.

* Le standard permet à uintptr_t d’être plus grand que le minimum, mais je suppose qu’il n’y a pas d’implémentation qui n’utilise pas le minimum.

Il est facile à résoudre si vous lancez le pointeur sur un type long. Le problème est que cela ne fonctionnera pas sur toutes les plates-formes car il suppose qu’un pointeur peut tenir dans une longue et qu’un pointeur peut être affiché en 16 caractères (64 bits). Cela est cependant vrai sur la plupart des plates-formes.

alors ça deviendrait:

 printf("%016lx", (unsigned long) ptr); 

Comme votre lien le suggère déjà, le comportement est indéfini. Je ne pense pas qu’il existe un moyen portable de le faire car% p lui-même dépend de la plate-forme sur laquelle vous travaillez. Vous pourriez bien sûr simplement lancer le pointeur sur un int et l’afficher en hexadécimal:

 printf("0x%016lx", (unsigned long)ptr); 

Peut-être que ce sera intéressant (à partir d’une machine Windows 32 bits, en utilisant mingw):

 rjeq@RJEQXPD /u $ cat test.c #include  int main() { char c; printf("p: %016p\n", &c); printf("x: %016llx\n", (unsigned long long) (unsigned long) &c); return 0; } rjeq@RJEQXPD /u $ gcc -Wall -o test test.c test.c: In function `main': test.c:7: warning: `0' flag used with `%p' printf format rjeq@RJEQXPD /u $ ./test.exe p: 0022FF77 x: 000000000022ff77 

Comme vous pouvez le constater, la version% p contient des zéros à la taille d’un pointeur, puis des espaces à la taille spécifiée, alors que l’utilisation de% x et des casts (les spécificateurs de format et de conversion sont hautement déplaçables) n’utilise que des zéros.

Notez que si le pointeur imprime avec le préfixe “0x”, vous devrez remplacer “% 018p” pour compenser.

J’utilise habituellement% x pour afficher les pointeurs. Je suppose que ce n’est pas portable aux systèmes 64 bits, mais cela fonctionne très bien pour les 32-bitters.

Je serai intéressé de voir quelles sont les réponses pour les solutions portables , car la représentation du pointeur n’est pas exactement portable.