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

StackOverflow https://stackoverflow.com/questions/1255099

  •  12-09-2019
  •  | 
  •  

Question

En C, je voudrais utiliser printf pour afficher les pointeurs, et de sorte qu'ils sont alignés correctement, j'aimerais pad avec 0s.

Je pense que la bonne façon de le faire est:

printf("%016p", ptr);

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

warning: '0' flag used with ‘%p’ gnu_printf format

J'ai googlé un peu, et le fil de discussion suivant est sur le même sujet, mais ne donne pas vraiment une solution.

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

De le lire, il semble que la raison pourquoi gcc se plaint, c'est que la syntaxe j'ai proposé n'est pas définie en C99.Mais je n'arrive pas à trouver d'autres moyens de faire la même chose dans une norme approuvée façon.

Voici donc la double question:

  • Est ma compréhension correcte que ce comportement n'est pas défini par le standard C99?
  • Si oui, est-il une norme approuvée, portable manière de procéder?
Était-ce utile?

La solution

#include <inttypes.h>

#include <stdint.h>

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

mais il ne sera pas imprimer le pointeur de la manière définie de mise en œuvre (dit DEAD:BEEF pour 8086 en mode segmenté).

Autres conseils

Utilisation:

#include <inttypes.h>

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

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

Notez également que certaines implémentations de printf() imprimer une « 0x » en face du pointeur; d'autres ne le font pas (et tous les deux sont corrects selon la norme C).

La seule portable moyen d'imprimer les valeurs de pointeur est d'utiliser la "%p" prescripteur, qui produit de l'implémentation de sortie définie.(La conversion de uintptr_t et à l'aide de PRIxPTR est susceptible de travailler, mais (un) uintptr_t a été introduit en C99, de sorte que certains compilateurs peuvent pas en charge, et (b) il n'est pas garanti, même en C99 (il ne peut pas être un type entier assez grand pour contenir tous les possibles valeurs de pointeur.

Donc de l'utiliser "%p" avec sprintf() (ou snprintf(), si vous en avez) pour imprimer une chaîne de caractères, puis imprimez la chaîne de remplissage avec de grands espaces.

Un problème est qu'il n'y a pas vraiment une bonne façon de déterminer la longueur maximale de la chaîne produite par "%p".

Ce n'est certes gênant (même si bien sûr, vous pouvez l'envelopper dans une fonction).Si vous n'avez pas besoin de 100% de la portabilité, je n'ai jamais utilisé un système de coulée le pointeur à unsigned long et l'impression du résultat à l'aide de "0x%16lx" ça ne marcherait pas.[Mise à JOUR:Oui, je l'ai.64-bit de Windows a pointeurs 64-bit et 32-bit unsigned long.] (Ou vous pouvez utiliser "0x%*lx" et de calculer la largeur, probablement quelque chose comme sizeof (void*) * 2.Si vous êtes vraiment paranoïaque, vous pouvez tenir compte pour les systèmes où la CHAR_BIT > 8, de sorte que vous aurez plus de 2 chiffres hexadécimaux par octet.)

Cette réponse est similaire à celle donnée plus tôt dans https://stackoverflow.com/a/1255185/1905491 mais aussi prend les largeurs possibles en compte (tel que décrit par https://stackoverflow.com/a/6904396/1905491 qui Je ne reconnais que ma réponse a été rendue en dessous;). Les éléments suivants Snipped imprimera pointeurs que 8 0 contournées caractères hexadécimaux sur les machines sains d'esprit * où ils peuvent être représentés par 32 bits, 16 sur 64b et 4 sur les systèmes 16b.

#include <inttypes.h>
#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 aller chercher la largeur par l'argument suivant, qui est en C99 (probablement avant?), Mais qui est tout à fait rarement vu « dans la nature ». Ceci est beaucoup mieux que d'utiliser la conversion de p parce que ce dernier est défini par l'implémentation.

* La norme permet uintptr_t d'être plus grand que le minimum, mais je suppose qu'il n'y a pas de mise en œuvre qui n'utilise pas le minimum.

Il est facile à résoudre si vous lancez le pointeur sur un type long. Le problème est cela ne fonctionnera pas sur toutes les plateformes car elle suppose un pointeur peut adapter à l'intérieur d'une longue et qu'un pointeur peut être affiché en 16 caractères (64 bits). Ceci est cependant vrai sur la plupart des plates-formes.

il deviendrait:

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

Comme votre lien l'indique, le comportement est indéfini. Je ne pense pas qu'il y ait un moyen portable de faire cela en% p lui-même dépend de la plate-forme sur laquelle vous travaillez. Vous pouvez bien sûr simplement jeté 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 <stdio.h>

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 voir, les% pads version p avec des zéros à la taille d'un pointeur, puis des espaces à la taille spécifiée, alors que l'utilisation de% x et moulages (les moulages et spécificateur de format sont très peu portable) utilise uniquement des zéros.

Notez que si les impressions de pointeur avec le « 0x » préfixe, vous devez remplacer « % 018p » pour compenser.

J'utilise habituellement% x pour afficher des pointeurs. Je suppose que ce n'est pas portable aux systèmes 64 bits, mais il fonctionne très bien pour 32-bitter.

Je suis curieux de voir quelles réponses il y a pour solutions portables , puisque la représentation du pointeur est pas exactement portable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top