Domanda

Oltre %hn e %hhn (dove i h o hh specifica la dimensione del punta a oggetto), qual è il punto di h e hh modificatori per identificatori di formato printf?

A causa promozioni che sono richiesti dalla norma da applicare Funzione Variadica di default, è impossibile passare argomenti di tipo char o short (o qualsiasi firmato / unsigned sue varianti) per printf.

Secondo 7.19.6.1 (7), il modificatore h:

Speci fi ca che un seguito d, i, o, u, x, o X conversione speci fi catore si applica ad un short int o unsigned short int argomento (la volontà argomento sono stati promossi secondo promozioni interi, ma il suo valore deve essere convertito in short int o unsigned short int prima della stampa); o che un seguito di conversione n speci fi catore si applica a un puntatore ad un corto argomento int.

Se l'argomento era effettivamente di tipo short o unsigned short, allora promozione per int seguita da una schiena conversione short o unsigned short produrrà lo stesso valore come promozione per int senza schienale conversione. Così, per gli argomenti di tipo short o unsigned short, %d, %u, ecc dovrebbe dare risultati identici a %hd, %hu, ecc (e similmente per tipi char e hh).

Per quanto posso dire, l'unica situazione in cui il modificatore h o hh potrebbe essere utile è quando l'argomento passò un int fuori della gamma di short o unsigned short, per esempio.

printf("%hu", 0x10000);

ma la mia comprensione è che passando il tipo sbagliato come questo si traduce in un comportamento indefinito in ogni caso, in modo che non si poteva aspettare per stampare 0.

Un caso mondo reale che ho visto è il codice come questo:

char c = 0xf0;
printf("%hhx", c);

in cui l'autore si aspetta per stampare f0 nonostante l'attuazione avendo un tipo char pianura che è firmato (in tal caso, sarebbe printf("%x", c) stampare fffffff0 o simili). Ma è questa aspettativa giustificata?

(Nota: Cosa sta succedendo è che il tipo originale era char, che viene promosso a int e ritorno convertito unsigned char invece di char, cambiando così il valore che viene stampato, ma non la norma specifica questo comportamento, o è. un dettaglio di implementazione che il software potrebbe essere rotto affidamento su?)

È stato utile?

Soluzione

Una possibile ragione: per la simmetria con l'uso di tali modificatori nelle funzioni di ingresso formattati? So che non sarebbe strettamente necessario, ma forse vi sia un valore visto per questo?

Anche se non menzionano l'importanza della simmetria per la "h" e modificatori "HH" in il documento C99 Rationale , la commissione fa menzione come una considerazione per cui il '' indicatore di conversione% p è supportato per fscanf() (anche se questo non era nuovo per C99 - "% p" supporto è in C90):

conversione puntatore ingresso con% p stato aggiunto al C89, anche se ovviamente rischioso, per simmetria con fprintf.

Nella sezione dedicata fprintf(), il documento logica C99 fa discutere che "hh" è stata aggiunta, ma semplicemente rimanda il lettore alla sezione fscanf():

sono stati aggiunti I modificatori di lunghezza% hh e LL% in C99 (vedi §7.19.6.2).

Lo so che è un filo tenue, ma sto speculando in ogni caso, così ho pensato che avrei dato qualunque argomento ci potrebbe essere.

Inoltre, per completezza, la "h" modificatore era nella norma C89 originale - presumibilmente sarebbe lì anche se non era strettamente necessario a causa di una diffusa uso esistenti, anche se non ci sarebbe stato un requisito tecnico per utilizzare il modificatore.

Altri suggerimenti

In modalità %...x, tutti i valori vengono interpretati come senza segno. I numeri negativi sono quindi stampati come loro conversioni senza segno. In 2 complemento di aritmetica, che la maggior parte dei processori usano, non v'è alcuna differenza di modelli di bit tra un numero negativo con segno e il suo equivalente senza segno positivo, che è definita dal modulo aritmetica (aggiungendo il valore massimo per il campo più uno del numero negativo, secondo allo standard C99). Un sacco di software- in particolare il codice di debug più propensi a utilizzare marche %x- l'ipotesi in silenzio che la rappresentazione po 'di un valore negativo firmato e il suo cast non firmato è la stessa, il che è vero solo sulla macchina di complemento a 2 del.

La meccanica di questo getto sono tali che le rappresentazioni esadecimali di valore implica sempre, forse erroneamente, che un numero è stato reso in complemento a 2, finché non ha colpito una condizione limite in cui le diverse rappresentazioni interi hanno differenti gamme. Questo vale anche vero per le rappresentazioni aritmetiche dove il valore 0 non è rappresentata con il modello binario di tutti 0.

Un short negativo visualizzato come unsigned long in esadecimale sarà pertanto, su qualsiasi macchina, essere imbottito con f, a causa di estensione del segno implicito nella promozione, che stamperà printf. valore è lo stesso, ma è veramente visivamente fuorviante circa la dimensione del campo, che implica una notevole quantità di gamma che semplicemente non è presente.

%hx tronca la rappresentazione visualizzata per evitare questo imbottiture, esattamente come avete concluso dal vostro caso d'uso nel mondo reale.

Il comportamento di printf è indefinito quando superato un int fuori della gamma di short che deve essere stampato come short, ma il più semplice attuazione di gran lunga semplicemente rigetti il ??bit alto da un'abbattuto greggio, così mentre la specifica non fa < em> richiedono qualsiasi comportamento specifico, praticamente qualsiasi applicazione sano di mente sta per solo eseguire il troncamento. Ci sono modi generalmente migliori per farlo, però.

Se printf non è imbottitura valori o la visualizzazione di rappresentazioni senza segno di valori con segno, %h non è molto utile.

L'unico uso che posso pensare è per il passaggio di un unsigned short o unsigned char e utilizzando l'indicatore di conversione %x. Non si può semplicemente utilizzare un %x nuda -. Il valore può essere promosso a int piuttosto che unsigned int, e poi ci sono un comportamento indefinito

Le alternative sono o per lanciare in modo esplicito l'argomento unsigned; o ad uso %hx / %hhx con un argomento nuda.

Gli argomenti variadic a printf() et al vengono promosse automaticamente in base alle conversioni predefinite, quindi i valori short o char sono promossi int quando viene passato alla funzione.

In assenza dei h o hh modificatori, che avrebbe dovuto mascherare i valori passati per ottenere il comportamento corretto in modo affidabile. Con i modificatori, non hai più a mascherare i valori; l'attuazione printf() fa correttamente il lavoro.

In particolare, per il formato %hx, il codice all'interno printf() può fare qualcosa di simile:

va_list args;
va_start(args, format);

...

int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!

Sono allegramente assumendo che short è una quantità a 16 bit; la norma in realtà non garantisce che, naturalmente.

Ho trovato utile per evitare la fusione nella formattazione di caratteri senza segno a esadecimale:

        sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));

E 'un minorenne di codifica vantaggio, e sembra più pulito di più calchi (IMO).

un altro posto che è a portata di mano è controllo della dimensione snprintf. gcc7 aggiunto controllo della dimensione quando si utilizza snprintf quindi questo fallirà

char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);

in modo che ti costringe a usare grande carattere quando si utilizza% d quando si formatta un char

ecco un commit che mostra le correzioni invece di aumentare la dimensione della matrice char hanno cambiato% d a% h. questo anche dare più accurata descrizione

https://github.com/Mellanox/libvma/commit/b5cb1e34a04b40427d195b14763e462a0a705d23 # diff-6258d0a11a435aa372068037fe161d24

Sono d'accordo con te che non è strettamente necessario, e così da solo per questo motivo non va bene in una funzione di libreria C:)

Potrebbe essere "bello" per la simmetria delle diverse bandiere, ma è soprattutto controproducente perché nasconde la "conversione a int" regola.

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