Domanda

In C, mi piacerebbe usare printf per visualizzare i puntatori, e in modo che siano allineati correttamente, mi piacerebbe loro pad con 0s.

La mia ipotesi è che il modo corretto di fare questo è stato:

printf("%016p", ptr);

Questo funziona, ma questo gcc si lamenta con il seguente messaggio:

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

Googled un po 'per questo, e il thread è sullo stesso argomento, ma non davvero dare una soluzione.

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

Leggendolo, sembra che il motivo per cui gcc si lamenta è che la sintassi ho suggerito non è definito nella C99. Ma io non riesco a trovare un altro modo per fare la stessa cosa in un modo standard approvato.

Così qui è la doppia domanda:

  • È la mia comprensione corretta che questo comportamento non è definito dallo standard C99?
  • Se è così, c'è una norma approvata, modo portabile di fare questo?
È stato utile?

Soluzione

#include <inttypes.h>

#include <stdint.h>

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

, ma non stamperà il puntatore nel modo definito implementazione (dice DEAD:BEEF per 8086 modo segmentato).

Altri suggerimenti

Usa:

#include <inttypes.h>

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

In alternativa, utilizzare un'altra variante delle macro da quel colpo di testa.

Si noti inoltre che alcune implementazioni di printf() stampare un '0x' davanti al puntatore; altri non lo fanno (ed entrambi sono corretti secondo lo standard C).

L'unico portatile modo per stampare i valori dei puntatori è utilizzare lo specificatore "%p", che produce in uscita implementazione definita. (Conversione in uintptr_t e utilizzando PRIxPTR è probabile che il lavoro, ma (a) uintptr_t è stato introdotto nel C99, in modo da alcuni compilatori non può sostenerlo, e (b) non è garantito ad esistere anche in C99 (ci potrebbe non essere un tipo integer abbastanza grande da contenere tutti i possibili valori di puntatore.

Così utilizzare "%p" con sprintf() (o snprintf(), se lo avete) per stampare su una stringa, e quindi stampare l'imbottitura stringa con spazi vuoti iniziali.

Un problema è che non c'è davvero un buon modo per determinare la lunghezza massima della stringa prodotta da "%p".

Questa è certamente scomodo (anche se naturalmente si può avvolgere in una funzione). Se non avete bisogno di portabilità al 100%, non ho mai usato un sistema sono stati gettando il puntatore unsigned long e stampare il risultato usando "0x%16lx" non avrebbe funzionato. [ Aggiorna : Sì, ho. 64-bit di Windows ha i puntatori a 64 bit e 32 bit unsigned long.] (Oppure è possibile utilizzare "0x%*lx" e calcolare la larghezza, probabilmente qualcosa come sizeof (void*) * 2. Se sei veramente paranoico, è possibile tenere conto di sistemi in cui CHAR_BIT > 8, in modo da' ll ottenere più di 2 cifre esadecimali per byte.)

Questa risposta è simile a quello dato in precedenza in https://stackoverflow.com/a/1255185/1905491 ma prende anche le larghezze possibili in considerazione (come indicato da https://stackoverflow.com/a/6904396/1905491 che non riconobbi finché la mia risposta è stata resa sotto di esso;). Quanto segue è stato tagliato stamperà puntatori come 8 caratteri esadecimali 0-passati su macchine sane * dove possono essere rappresentati da 32 bit, 16 su 64b e 16b 4 su sistemi.

#include <inttypes.h>
#define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))

printf("0x%0*" PRIxPTR, PRIxPTR_WIDTH, (uintptr_t)pointer);

Si noti l'uso del carattere asterisco per andare a prendere la larghezza con l'argomento successivo, che è in C99 (probabilmente prima?), Ma che è abbastanza raramente visto "in the wild". Questo è il modo migliore di usare la conversione p perché quest'ultimo è definito dall'implementazione.

* Lo standard consente uintptr_t ad essere più grande rispetto al minimo, ma suppongo non ci sono implementazioni che non utilizza il minimo.

E 'facile da risolvere se si esegue il cast il puntatore ad un tipo lungo. Il problema è questo non funziona su tutte le piattaforme assume una puntatore può essere contenuto in una lunga, e che un puntatore può essere visualizzato in 16 caratteri (64 bit). Questo è comunque vero sulla maggior parte delle piattaforme.

in modo che sarebbe diventato:

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

Come il tuo link suggerisce già, il comportamento è indefinito. Non credo ci sia un modo di fare questo portatile come% p stessa dipende dalla piattaforma su cui state lavorando. Si potrebbe naturalmente solo il cast del puntatore a un int e visualizzarli in esadecimale:

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

Forse questo sarà interessante (da una macchina Windows a 32 bit, usando 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

Come si può vedere, le pastiglie versione% p con zeri alla dimensione di un puntatore, e poi spazi alla dimensione specificata, mentre utilizzando% x e calchi (i calchi e di formato sono altamente portabile) utilizza solo zeri.

Si noti che se le stampe puntatore con il prefisso "0x", si avrebbe bisogno di sostituire "% 018p" per compensare.

Io di solito uso% x per visualizzare i puntatori. Suppongo che non è portabile su sistemi a 64 bit, ma funziona bene per 32-amari.

Sarò interessato a vedere quali risposte ci sono per soluzioni portatili , dal momento che la rappresentazione puntatore non è esattamente portatile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top