2009-07-26 8 views
16

Durante la ricerca su come eseguire le stringhe di formato multipiattaforma printf() in C (ovvero, tenendo conto del numero di bit che mi aspetto che ogni argomento intero su printf() debba essere), ho trovato this section of the Wikipedia article on printf(). L'articolo discute opzioni non standard che possono essere passati al printf() stringhe di formato, come ad esempio (quello che sembra essere un estensione di Microsoft-specifico):Perché non sono state utilizzate stringhe di opzione di formato printf() nuove (larghezza del bit) come parte di C99?

printf("%I32d\n", my32bitInt); 

E prosegue affermando che:

ISO C99 include il file inttypes.h di intestazione che include un numero di macro da utilizzare nella codifica di stampa indipendente dalla piattaforma .

... e quindi elenca un set di macro che è possibile trovare in tale intestazione. Guardando il file di intestazione, per usarli dovrei scrivere:

printf("%"PRId32"\n", my32bitInt); 

La mia domanda è: mi manca qualcosa? Questo è davvero il modo standard C99 per farlo? Se è così, perché? (Anche se non mi sorprende che non abbia mai visto il codice che utilizza le stringhe di formato in questo modo, dal momento che sembra così ingombrante ...)

risposta

16

Il C Razionale sembra implicare che <inttypes.h> sta standardizzando pratiche esistenti:

<inttypes.h> è stato derivato dalla testata con lo stesso nome trovato in molti a 64 bit esistente sistemi.

ma il resto del testo non scrive su quelle macro e non ricordo che esistessero pratiche in quel momento.

Quello che segue è solo speculazione, ma educato dall'esperienza di come funzionano i comitati di standardizzazione.

Uno dei vantaggi delle macro C99 oltre standardizzazione ulteriore identificatore di formato per printf (si noti che C99 ha fatto anche aggiungere un po ') è che fornire <inttypes.h> e <stdint.h> quando si dispone già di un'implementazione supportare le caratteristiche richieste in maniera specifica implementazione è solo scrivendo due file con typedef e macro adeguati. Ciò riduce il costo di rendere conforme l'implementazione esistente, riduce il rischio di rompere i programmi esistenti che hanno fatto uso delle caratteristiche specifiche dell'implementazione esistente (il modo standard non interferisce) e facilita il porting di programmi conformi all'implementazione che non hanno questi intestazioni (possono essere fornite dal programma). Inoltre, se le modalità specifiche di implementazione già variate al momento, non favoriscono un'implementazione rispetto a un'altra.

+0

Uno svantaggio: chiamare C dal montaggio. –

8

Corretto, questo è come lo standard C99 dice che dovresti usarli. Se si desidera che il codice portablt sia conforme agli standard del 100% alla lettera, è necessario stampare sempre uno int utilizzando "%d" e un int32_t utilizzando "%"PRId32.

La maggior parte delle persone non si preoccupa, tuttavia, dal momento che ci sono pochissimi casi in cui la mancata osservanza di tale scelta sarebbe importante. A meno che non porti il ​​tuo codice su Win16 o DOS, puoi supporre che sia sizeof(int32_t) <= sizeof(int), quindi è innocuo stampare accidentalmente uno int32_t come int. Allo stesso modo, un long long è praticamente universalmente 64 bit (anche se non è garantito che sia così), quindi la stampa di int64_t come long long (ad esempio con un identificatore %llx) è sicura.

I tipi int_fast32_t, int_least32_t e così via non vengono quasi mai utilizzati, quindi è possibile immaginare che i rispettivi specificatori di formato siano utilizzati anche più raramente.

+0

"La mia domanda è: mi sto perdendo qualcosa È davvero questo il modo standard C99 per farlo ** Se è così, perché **???" –

+0

Anche se mi piacerebbe davvero conoscere il "perché" parte, mi rendo conto che è in qualche modo una domanda retorica. Dubito che qualcuno lo saprebbe, a meno che non partecipino alla discussione presso le organizzazioni di standard quando si parlava del C99. Sto immaginando un gruppo di ingegneri che discutono sul merito di richiedere modifiche a printf() quando avevano già stringhe di formato per stampare qualsiasi cosa. Probabilmente hanno appena deciso di renderlo un #define e averlo fatto. Quindi, a meno che qualcun altro abbia qualche intuizione profonda qui, probabilmente accetterò questa risposta; risponde alla maggior parte della mia domanda. – mpontillo

+1

Forse scrivo troppo codice incorporato, ma sono un grande fan dell'uso dei macro 'PRIx ##' nelle mie stringhe printf. Suppongo solo che 'int' sia 16 bit o superiore. Dopo averlo fatto per un po ', ti ci abitui. – tomlogic

1

Posso solo speculare sul perché. Mi piace la risposta di AProgrammer sopra, ma c'è un aspetto sottovalutato: che cosa aggiungerai a printf come modificatore di formato? Esistono già due modi diversi per utilizzare i numeri in una stringa di formato printf (larghezza e precisione). Aggiungere un terzo tipo di numero per dire quanti bit di precisione sono nell'argomento sarebbe fantastico, ma dove lo metterai senza confondere le persone? Sfortunatamente uno dei difetti di C è che printf non è stato progettato per essere estensibile.

Le macro sono orribili, ma quando si deve scrivere codice che è portatile su piattaforme a 32 e 64 bit, sono una manna dal cielo. Sicuramente ho salvato il mio bacon.

Penso che la risposta alla tua domanda perché è o

  • Nessuno poteva pensare ad un modo migliore per farlo, o
  • Standards Committee non poteva d'accordo su tutto quello che provavo era chiaramente meglio.
+0

Un buon punto, ma Microsoft ha aggiunto un modo per farlo usando un modificatore di formato (che è brutto ma funziona). Un modo sarebbe stato quello di disaccoppiare la corrente "d = int, u = unsigned int" pensando e riassegnare gli specificatori di tipo tali che "d = int32_t, u = uint32_t". Questo potrebbe essere stato meno distruttivo per C rispetto alla rotta Java. (specificare la larghezza del bit di ogni tipo in modo esplicito, che probabilmente avrebbero dovuto fare inizialmente ...) Ma avrebbe comunque richiesto modifiche alle implementazioni di printf(). Penso che abbiano appena preso la via più facile. – mpontillo

+0

@Mike: hai un puntatore al modo Microsoft? Odio i macro. E ho già implementato la maggior parte di un'implementazione di printf. –

+0

È stato menzionato sull'articolo di Wikipedia che ho collegato, ma qui è direttamente dalla fonte: http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx – mpontillo

1

Un'altra possibilità: retrocompatibilità. Se si aggiungono più specificatori di formato a printf o opzioni aggiuntive, è possibile che uno specificatore in un codice pre-C99 abbia una stringa di formato interpretata in modo diverso.

Con la modifica C99, non si modifica la funzionalità di printf.

2

È sempre possibile eseguire il cast verso l'alto e utilizzare %jd che è l'identificatore di formato intmax_t.

printf("%jd\n", (intmax_t)(-2)); 

ho usato intmax_t di dimostrare che qualsiasi intXX_t può essere utilizzato, ma semplicemente la fusione di long è molto meglio per il caso int32_t, quindi utilizzare %ld.

+0

+1 per l'idea interessante, ma non sono sicuro che mi piaccia l'idea di lanciare potenzialmente un numero intero a 32 bit su un valore + 64 bit su un sistema embedded ... mi sento in qualche modo sbagliato in qualche modo. ;-) – mpontillo

+0

quando si utilizza 'printf', sprecare 4 byte per l'archiviazione temporanea (se non del tutto) è l'ultimo dei tuoi problemi di prestazioni! ;) – lambdapower

Problemi correlati