printf

funzione implementata nei linguaggi di programmazione

printf è una funzione implementata nei linguaggi di programmazione per visualizzare sullo standard output una stringa costruita in base ad un formato specificato. Tale funzione ha origine dal linguaggio C, dove ha un prototipo simile al seguente:

int printf(const char *format, ...)

Il parametro format è una stringa che descrive il formato da seguire nell'output e che utilizza delle sequenze segnaposto, introdotte dal simbolo percentuale ("%"), per specificare la posizione relativa e il tipo dei dati con cui comporre la stringa.

Per esempio, nel linguaggio C

printf("Colore %s, numero1 %d, numero2 %05d, hex %x, float %5.2f.\n",
             "rosso", 123456, 89, 255, 3.14);

stamperà la seguente linea (escluso il carattere di nuova linea, \n):

Colore rosso, numero1 123456, numero2 00089, hex ff, float 3.14.

La funzione printf restituisce il numero di caratteri stampati, o un numero negativo se si è verificato un errore di output.

Anche il Perl ha la funzione printf ma per la conversione usa caratteri differenti. Python ha una funzionalità analoga (l'operatore %). La libreria GLib contiene la funzione g_print, un'implementazione di printf.

I sistemi POSIX dispongono di un programma denominato printf[1], utilizzabile ad esempio negli script di shell; può essere impiegato in sostituzione del comando echo in situazioni in cui quest'ultimo non sia portabile.

Per esempio:

echo -n -e "$FOO\t$BAR'

può essere riscritto in modo portabile come:

printf '%s\t%s' "$FOO" "$BAR"

Anche il linguaggio PHP dispone della funzione printf, uguale a quella del C/C++.
Nel programma MATLAB non è presente printf, ma sono disponibili due sue estensioni: sprintf e fprintf, che accettano la stessa sintassi nella stringa di formato.

Il linguaggio JavaScript, nonostante sia un linguaggio di programmazione di tipologia curly bracket, non dispone di una funzione printf.

Funzioni derivate modifica

Lo Standard C specifica alcune funzioni derivate da printf che permettono di estenderne gli usi:

fprintf modifica

int fprintf(FILE *stream, const char *format, ...)

fprintf permette la scrittura dell'output su file. Questa funzione viene spesso impiegata per scrivere sullo standard error o su file di testo. In realtà può essere utilizzata per scrivere su qualsiasi file o stream aperto con la funzione fopen, anche se l'utilizzo di fprintf per la scrittura di dati binari può risultare problematica o quantomeno scomoda.

sprintf modifica

int sprintf (char *str, const char *format, ...)

sprintf stampa su una stringa (array di char) anziché sullo standard output. Gli utenti devono accertarsi, attraverso il calcolo o lo stack-smashing protection, che la stringa risultante non sia più lunga della memoria allocata per str. Non accertarsi di questo può causare un buffer overflow.

È da notare che in PHP la funzione sprintf non possiede l'argomento str; al contrario, la funzione restituisce la stringa di output formattata.

Il prototipo della funzione in PHP è:

string sprintf (const string format, ...)

Un'alternativa sicura a sprintf modifica

Come alternativa, molti ambienti forniscono la funzione snprintf:

int snprintf(char *str, size_t size, const char *format, ...)

snprintf garantisce di non scrivere più di size bytes in str, in modo da evitare il rischio di un buffer overflow, come nel codice seguente:

#define BUFFER_SIZE 50
char buf[BUFFER_SIZE];
int n;

...

n = snprintf(buf, BUFFER_SIZE, "Your name is %s.\n", username);
if (n < 0 || n >= BUFFER_SIZE)
   /* Handle error */

Se username nell'esempio precedente è più lungo di 50 caratteri, la funzione limiterà la stringa che viene salvata in buf troncando i caratteri finali. Ciò può sembrare indesiderabile, tuttavia preferibile ad avere una vulnerabilità di sicurezza, a cui un buffer overflow può condurre spesso. Inoltre, il codice di ritorno della funzione snprintf indica quanti caratteri la funzione avrebbe scritto sulla stringa con spazio sufficiente. I sistemi possono usare questa informazione per allocare un nuovo buffer (più grande) se hanno bisogno di tutta la stringa non troncata.

snprintf non è parte del largamente implementato standard ANSI C, come la sprintf. Tuttavia, entra a far parte del linguaggio con lo standard C99 e spesso era presente nelle librerie C anche prima di questo standard.

Un'altra alternativa sicura a sprintf è asprintf:

int asprintf(char **ret, const char *format, ...)

asprintf alloca automaticamente memoria sufficiente per contenere la stringa finale. La funzione inizializza *ret con un puntatore alla stringa risultante o con un valore indefinito se si verifica un errore (È da notare che la Glibc è l'unica implementazione che non sempre inizializza *ret a NULL nel caso in cui si verifichi un errore). Il programmatore, nell'usare la asprintf, ha la responsabilità di liberare la memoria allocata dopo l'uso. Sebbene non sia parte di alcuno standard, asprintf è inclusa nelle librerie C di molti sistemi operativi (inclusi OpenBSD, FreeBSD e NetBSD).

vprintf, vfprintf, vsprintf, vsnprintf, and vasprintf modifica

int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int vasprintf(char **ret, const char *format, va_list ap);

Queste funzioni sono analoghe a quelle precedenti senza la v, tranne che per il fatto di usare delle liste di argomenti variabili. Queste funzioni offrono la possibilità ai programmatori di creare le proprie varianti della printf. Per esempio, un programmatore potrebbe scrivere una funzione

void fatal_error(const char *format, ...)

Che userebbe la macro va_start per avere una variabile va_list dai parametri extra, stampa un messaggio sul dispositivo di errore standard usando vfprintf, dopo la variabile va_list pulisce con la macro va_end, e alla fine esegue i compiti necessari per chiudere il programma liberando la memoria.

Un'altra applicazione comune di queste funzioni è scrivere un printf arbitrario che stampi su un oggetto diverso da un file. Una libreria grafica può fornire funzioni simili a printf con coordinate x e y:

int graphical_printf(int x, int y, const char *format, ...)

Questo salverebbe temporaneamente la stringa su un buffer privato usando vsnprintf o vasprintf.

Segnaposti del formato printf modifica

La formattazione avviene attraverso segnaposti nella stringa di formato. Per esempio, se un programma vuole stampare l'età di una persona, può presentare l'output con il prefisso "la tua età è". Per specificare che vogliamo che l'integer dell'età venga stampato dopo il messaggio possiamo usare la forma:

"la tua eta' e' %d."

la sintassi del segnaposto di formato è "%[flag][larghezza][.precisione][lunghezza]tipo".

tipo può essere:

  • 'd', 'i' : stampa un intero come decimale con segno. '%d' e '%i' sono sinonimi per l'output, ma diversi se usati con scanf() per l'input;
  • 'u' : stampa un intero come decimale senza segno;
  • 'f', 'F' : Stampa un valore reale come un numero con virgola;
  • 'e', 'E' : Stampa un valore reale nella forma esponenziale standard ([-]d.ddd e[+/-]ddd); 'e' usa la 'e' minuscola, 'E' usa la maiuscola;
  • 'g', 'G' : Stampa un valore reale con notazione reale o esponenziale, scegliendo quella più adatta alla sua dimensione. 'g' usa lettere minuscole, 'G' usa lettere maiuscole. Questa notazione è diversa dalla notazione con virgola perché gli zeri superflui alla destra del punto decimale non sono inclusi. Il punto decimale non è incluso nei numeri interi;
  • 'x', 'X' : Stampa un intero senza segno come numero esadecimale. 'x' usa lettere minuscole e 'X' usa maiuscole;
  • 'o' : Stampa un intero senza segno in base ottale;
  • 's' : Stampa una stringa;
  • 'c' : Stampa un carattere;
  • 'p' : Stampa un puntatore a void, in un formato definito dall'implementazione;
  • 'n' : Scrivi il numero di caratteri finora scritti correttamente in un parametro puntatore a intero;
  • '%' : stampa un carattere '%' (non accetta flag, precisione, lunghezza o larghezza).

I flag si possono omettere:

  • '+' : Printf denota sempre il segno '+' o '-' di un numero (il default è omettere il segno per i numeri positivi). Solo per variabili numeriche.
  • '-' : Printf allinea a sinistra l'output di questo segnaposto (il default è a destra).
  • '#' : Forma alternata: con 'g' e 'G', gli zeri finali non sono rimossi; con 'f', 'F', 'e', 'E', 'g', 'G', l'output contiene sempre un punto decimale; con 'o', 'x', e 'X', vengono rispettivamente prefissi uno 0, 0x, o 0Xai numeri diversi da zero.
  • ' ' : Fa inserire a printf spazi sulla sinistra dell'output fino al raggiungimento della larghezza richiesta. Se combinato con '0' (vedi sotto), farà diventare il segno uno spazio per i numeri positivi, ma gli altri caratteri saranno riempiti da zeri.
  • '0' : Fa usare a printf dei caratteri '0' (anziché spazi) a sinistra fino al raggiungimento di una certa larghezza. Per esempio, assumendo i = 3, printf("%2d", i) risulta in " 3", mentre printf("%02d", i) risulta in "03"

La larghezza può essere omessa, o essere:

  • un numero : printf mostra l'output di questo segnaposto con spazi finché è largo almeno numero caratteri.
  • '*' : printf espande l'output finché è largo n caratteri, dove n è un valore intero memorizzato nel prossimo argomento. Per esempio printf("%*d", 5, 10) risulterà in "10" stampato con una larghezza pari a 5.

La precisione può essere omessa, o essere:

  • un numero : Per i tipi numerici non interi (cioè a virgola mobile), la porzione decimale dell'output viene espressa con esattamente numero cifre. Con le stringhe, taglia l'output a numero caratteri.
  • '*' : Come sopra, ma usa un valore intero nell'argomento successivo per determinare il numero di posizioni decimali o la massima lunghezza della stringa. Per esempio, printf("%.*s", 3, "abcdef") risulterà nella stampa di "abc".

La lunghezza può essere omessa, o essere:

  • 'hh' : per i tipi interi, printf si attende un argomento lungo quanto un char;
  • 'h' : per i tipi interi, printf si attende un argomento lungo quanto un intero corto;
  • 'l' : (elle) per i tipi interi, printf si attende un argomento lungo quanto un intero lungo;
  • 'll' : (elle elle) per i tipi interi, printf si attende un argomento lungo quanto un intero lungo-lungo;
  • 'L' : per i tipi a virgola mobile, printf si attende un argomento lungo quanto un doppio lungo;
  • 'z' : per i tipi interi, printf si attende un argomento lungo quanto un intero di tipo size_t;
  • 'j': per i tipi interi, printf si attende un argomento lungo quanto un intero di tipo intmax_t;
  • 't': per i tipi interi, printf si attende un argomento lungo quanto un intero di tipo ptrdiff_t.

Se la sintassi di una specifica di conversione non è valida, il comportamento non è definito. Se ci sono troppo pochi argomenti di funzione dati per fornire i valori per tutte le specifiche di conversione nella stringa di modello, o se gli argomenti non sono dei tipi giusti, i risultati non sono definiti. Gli argomenti in eccesso vengono ignorati. In alcuni casi il comportamento non definito ha portato ad attacchi contro la sicurezza basati sul formato della stringa. Nota che alcuni compilatori, come GCC, controlleranno alla compilazione le stringhe di formato di printf come fossero funzioni, e segnaleranno eventuali problemi.

La maggior parte dei linguaggi non-C hanno una funzione come printf che lavorano usando il codice di formattazione "%s" e convertendo gli oggetti in testo. Il C++ offre un nuovo modo di eseguire printf. Il C++ infatti include la funzione printf in un nuovo meccanismo completamente diverso, che è generalmente preferito.

Linguaggi di programmazione con printf modifica

Note modifica

  1. ^ (EN) printf, in The Open Group Base Specifications Issue 7 IEEE Std 1003.1-2008. URL consultato il 30 marzo 2010.

Voci correlate modifica

Collegamenti esterni modifica

  Portale Informatica: accedi alle voci di Wikipedia che trattano di informatica