 \chapter{I file: l'interfaccia standard ANSI C}
\label{cha:files_std_interface}

Esamineremo in questo capitolo l'interfaccia standard ANSI C per i file,
quella che viene comunemente detta interfaccia degli \textit{stream}.
Dopo una breve sezione introduttiva tratteremo le funzioni base per la
gestione dell'input/output, mentre tratteremo le caratteristiche più avanzate
dell'interfaccia nell'ultima sezione.


\section{Introduzione}
\label{sec:file_stream_intro}

Come visto in \capref{cha:file_unix_interface} le operazioni di I/O sui file
sono gestibili a basso livello con l'interfaccia standard unix, che ricorre
direttamente alle system call messe a disposizione dal kernel.

Questa interfaccia però non provvede le funzionalità previste dallo standard
ANSI C, che invece sono realizzate attraverso opportune funzioni di libreria,
queste, insieme alle altre funzioni definite dallo standard, vengono a
costituire il nucleo\footnote{queste funzioni sono state implementate la prima
  volta da Ritchie nel 1976 e da allora sono rimaste sostanzialmente
  immutate.} delle \acr{glibc}.


\subsection{I \textit{file stream}}
\label{sec:file_stream}

Come più volte ribadito l'interfaccia dei file descriptor è una interfaccia di
basso livello, che non provvede nessuna forma di formattazione dei dati e
nessuna forma di bufferizzazione per ottimizzare le operazioni di I/O.

In \textit{Advanced Programming in the Unix Environment} Stevens descrive una
serie di test sull'influenza delle dimensioni del blocco di dati (il parametro
\param{buf} di \func{read} e \func{write}) nell'efficienza nelle operazioni di
I/O con i file descriptor, evidenziando come le prestazioni ottimali si
ottengano a partire da dimensioni del buffer dei dati pari a quelle dei
blocchi del filesystem (il valore dato dal campo \var{st\_blksize} di
\var{fstat}).

Se il programmatore non si cura di effettuare le operazioni in blocchi di
dimensioni adeguate, le prestazioni sono inferiori.  La caratteristica
principale dell'interfaccia degli stream è che essa provvede da sola alla
gestione dei dettagli della bufferizzazione e all'esecuzione delle operazioni
di lettura e scrittura in blocchi di dimensioni appropriate all'ottenimento
della massima efficienza.

Per questo motivo l'interfaccia viene chiamata anche interfaccia dei
\textit{file stream}, dato che non è più necessario doversi preoccupare
dei dettagli della comunicazione con il tipo di hardware sottostante
(come nel caso della dimensione dei blocchi del filesystem), ed un file
può essere sempre considerato come composto da un flusso continuo (da
cui il nome \textit{stream}) di dati.

A parte i dettagli legati alla gestione delle operazioni di lettura e
scrittura (sia per quel che riguarda la bufferizzazione, che le
formattazioni), i file stream restano del tutto equivalenti ai file descriptor
(sui quali sono basati), ed in particolare continua a valere quanto visto in
\secref{sec:file_sharing} a proposito dell'accesso condiviso ed in
\secref{sec:file_access_control} per il controllo di accesso.


\subsection{Gli oggetti \type{FILE}}
\label{sec:file_FILE}

Per ragioni storiche la struttura di dati che rappresenta uno stream è stata
chiamata \type{FILE}, questi oggetti sono creati dalle funzioni di libreria e
contengono tutte le informazioni necessarie a gestire le operazioni sugli
stream, come la posizione corrente, lo stato del buffer e degli indicatori di
stato e di fine del file.

Per questo motivo gli utenti non devono mai utilizzare direttamente o
allocare queste strutture, ma usare sempre puntatori del tipo \type{FILE
  *} ottenuti dalla libreria stessa (tanto che in certi casi il termine
di puntatore a file è diventato sinonimo di stream).  Tutte le funzioni
della libreria che operano sui file accettano come parametri solo
variabili di questo tipo, che diventa accessibile includendo l'header
file \file{stdio.h}.



\subsection{Gli stream standard}
\label{sec:file_std_stream}

Ai tre file descriptor standard (vedi \secref{sec:file_std_descr})
aperti per ogni processo, corrispondono altrettanti stream, che
rappresentano i canali standard di input/output prestabiliti; anche
questi tre stream sono identificabili attraverso dei nomi simbolici
definiti nell'header \file{stdio.h} che sono:

\begin{itemize}
\item \var{FILE *stdin} Lo \textit{standard input} cioè lo stream da
  cui il processo riceve ordinariamente i dati in ingresso. Normalmente
  è associato dalla shell all'input del terminale e prende i caratteri
  dalla tastiera.
\item \var{FILE *stdout} Lo \textit{standard input} cioè lo stream su
  cui il processo invia ordinariamente i dati in uscita. Normalmente è
  associato dalla shell all'output del terminale e scrive sullo schermo.
\item \var{FILE *stderr} Lo \textit{standard input} cioè lo stream su
  cui il processo è supposto inviare i messaggi di errore. Normalmente
  anch'esso è associato dalla shell all'output del terminale e scrive
  sullo schermo.
\end{itemize}

Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono
effettivamente tre variabili di tipo \type{FILE *} che possono essere
usate come tutte le altre, ad esempio si può effettuare una redirezione
dell'output di un programma con il semplice codice:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
    fclose (stdout);
    stdout = fopen ("standard-output-file", "w");
\end{lstlisting}
ma in altri sistemi queste variabili possono essere definite da macro, e
se si hanno problemi di portabilità e si vuole essere sicuri, diventa
opportuno usare la funzione \func{freopen}.


\subsection{Le modalità di bufferizzazione}
\label{sec:file_buffering}

La bufferizzazione è una delle caratteristiche principali della
interfaccia degli stream; lo scopo è quello di ridurre al minimo il
numero di system call (\func{read} o \func{write}) eseguite nelle
operazioni di input/output. Questa funzionalità è assicurata
automaticamente dalla libreria, ma costituisce anche una degli aspetti
più comunemente fraintesi, in particolare per quello che riguarda
l'aspetto della scrittura dei dati sul file.

I caratteri che vengono scritti su uno stream normalmente vengono
accumulati in un buffer e poi trasmessi in blocco in maniera asincrona
rispetto alla scrittura (quello che viene chiamato lo \textsl{scarico}
dei dati, dall'inglese \textit{flush}) tutte le volte che il buffer
viene riempito. Un comportamento analogo avviene anche in lettura (cioè
dal file viene letto un blocco di dati, anche se se ne sono richiesti
una quantità inferiore), ma la cosa ovviamente ha rilevanza inferiore,
dato che i dati letti sono sempre gli stessi; in caso di scrittura
invece, quando si ha un accesso contemporaneo allo stesso file (ad
esempio da parte di un altro processo) si potranno vedere solo le parti
effettivamente scritte, e non quelle ancora presenti nel buffer.

Allo stesso modo, se si sta facendo dell'input/output interattivo
bisognerà tenere presente le caratteristiche delle operazioni di scarico
dei dati, poiché non è detto che ad una scrittura sullo stream
corrisponda una immediata scrittura sul dispositivo.

Per rispondere ad esigenze diverse, lo standard definisce tre distinte
modalità in cui può essere eseguita la bufferizzazione, delle quali
occorre essere ben consapevoli, specie in caso di lettura e scrittura da
dispositivi interattivi:
\begin{itemize}
\item \textit{unbuffered}: in questo caso non c'è bufferizzazione ed i
  caratteri vengono trasmessi direttamente al file non appena possibile
  (effettuando immediatamente una \func{write}).
\item \textit{line buffered}: in questo caso i caratteri vengono
  normalmente trasmessi al file in blocco ogni volta che viene
  incontrato un carattere di \textit{newline} (il carattere ASCII
  \verb|\n|).
\item \textit{fully buffered}: in questo caso i caratteri vengono
  trasmessi da e verso il file in blocchi di dimensione opportuna.
\end{itemize}

Lo standard ANSI C specifica inoltre che lo standard output e lo
standard input siano aperti in modalità \textit{fully buffered} quando
non fanno riferimento ad un dispositivo interattivo, e che lo standard
error non sia mai aperto in modalità \textit{fully buffered}.

Linux, come BSD e SVr4, specifica il comportamento di default in maniera
ancora più precisa, e cioè impone che lo standard error sia sempre
\textit{unbuffered} (in modo che i messaggi di errore siano mostrati il più
rapidamente possibile) e che standard input e standard output siano aperti in
modalità \textit{line buffered} quando sono associati ad un terminale (od
altro dispositivo interattivo) ed in modalità \textit{fully buffered}
altrimenti.

Il comportamento specificato per standard input e standard output vale anche
per tutti i nuovi stream aperti da un processo; la selezione comunque avviene
automaticamente, e la libreria apre lo stream nella modalità più opportuna a
seconda del file o del dispositivo scelto.

La modalità \textit{line buffered} è quella che necessita di maggiori
chiarimenti e attenzioni per quel che concerne il suo funzionamento. Come già
accennato nella descrizione, \emph{di norma} i dati vengono inviati al kernel
alla ricezione di un carattere di a capo; questo non è vero in tutti i casi,
infatti, dato che le dimensioni del buffer usato dalle librerie sono fisse, se
le si eccedono si può avere uno scarico dei dati anche prima che sia stato
inviato un carattere di \textit{newline}.

Un secondo punto da tenere presente, particolarmente quando si ha a che fare
con I/O interattivo, è che quando si effettua una lettura su uno stream che
comporta l'accesso al kernel\footnote{questo vuol dire sempre se lo stream da
  cui si legge è in modalità \textit{unbuffered}.} viene anche eseguito lo
scarico di tutti i buffer degli stream in scrittura.

In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
opportune funzioni per controllare le modalità di bufferizzazione e lo scarico
dei dati.



\section{Funzioni base}
\label{sec:file_ansi_base_func}

Esamineremo in questa sezione le funzioni base dell'interfaccia degli stream,
analoghe a quelle di \secref{sec:file_base_func} per i file descriptor. In
particolare vedremo come aprire, leggere, scrivere e cambiare la posizione
corrente in uno stream.


\subsection{Apertura e chiusura di uno stream}
\label{sec:file_fopen}

Le funzioni che si possono usare per aprire uno stream sono solo
tre\footnote{\func{fopen} e \func{freopen} fanno parte dello standard
  ANSI C, \func{fdopen} è parte dello standard POSIX.1.}, i loro
prototipi sono:
\begin{functions}
  \headdecl{stdio.h}
  \funcdecl{FILE *fopen(const char *path, const char *mode)}
  Apre il file specificato da \param{path}.
  \funcdecl{FILE *fdopen(int fildes, const char *mode)}
  Associa uno stream al file descriptor \param{fildes}.
  \funcdecl{FILE *freopen(const char *path, const char *mode, FILE *stream)}
  Apre il file specificato da \param{path} associandolo allo stream
  specificato da \param{stream}, se questo è già aperto prima lo chiude.
  
  \bodydesc{Le funzioni ritornano un puntatore valido in caso di
    successo e \macro{NULL} in caso di errore, in tal caso \var{errno}
    viene settata al valore ricevuto dalla funzione sottostante di cui è
    fallita l'esecuzione.
  
    Gli errori pertanto possono essere quelli di \func{malloc} per tutte
    e tre le funzioni, quelli \func{open} per \func{fopen}, quelli di
    \func{fcntl} per \func{fdopen} e quelli di \func{fopen},
    \func{fclose} e \func{fflush} per \func{freopen}.}
\end{functions}

Normalmente la funzione che si usa per aprire uno stream è \func{fopen},
essa apre il file specificato nella modalità specificata da
\param{mode}, che è una stringa che deve iniziare con almeno uno dei
valori indicati in \tabref{tab:file_fopen_mode} (sono possibili varie
estensioni che vedremo in seguito).

L'uso più comune di \func{freopen} è per redirigere uno dei tre file
standard (vedi \secref{sec:file_std_stream}): il file \param{path} viene
associato a \param{stream} e se questo è uno stream già aperto viene
preventivamente chiuso.

Infine \func{fdopen} viene usata per associare uno stream ad un file
descriptor esistente ottenuto tramite una altra funzione (ad esempio con
una \func{open}, una \func{dup}, o una \func{pipe}) e serve quando si
vogliono usare gli stream con file come le fifo o i socket, che non
possono essere aperti con le funzioni delle librerie standard del C.

\begin{table}[htb]
  \centering
  \begin{tabular}[c]{|l|p{8cm}|}
    \hline
    \textbf{Valore} & \textbf{Significato}\\
    \hline
    \hline
    \texttt{r} & Il file viene aperto, l'accesso viene posto in sola
    lettura, lo stream è posizionato all'inizio del file.\\
    \texttt{r+} & Il file viene aperto, l'accesso viene posto in lettura e
    scrittura, lo stream è posizionato all'inizio del file. \\
%    \hline
    \texttt{w} & Il file viene aperto e troncato a lunghezza nulla (o
    creato se non esiste), l'accesso viene posto in sola scrittura, lo
    stream è posizionato all'inizio del file.\\
    \texttt{w+} & Il file viene aperto e troncato a lunghezza nulla (o
    creato se non esiste), l'accesso viene posto in scrittura e lettura,
    lo stream è posizionato all'inizio del file.\\
%    \hline
    \texttt{a} & Il file viene aperto (o creato se non esiste) in
    \textit{append mode}, l'accesso viene posto in sola scrittura. \\
    \texttt{a+} & Il file viene aperto (o creato se non esiste) in
    \textit{append mode}, l'accesso viene posto in lettura e scrittura. \\
    \hline
  \end{tabular}
  \caption{Modalità di apertura di uno stream dello standard ANSI C che
    sono sempre presenti in qualunque sistema POSIX}
  \label{tab:file_fopen_mode}
\end{table}

In realtà lo standard ANSI C prevede un totale di 15 possibili valori
diversi per \param{mode}, ma in \tabref{tab:file_fopen_mode} si sono
riportati solo i sei valori effettivi, ad essi può essere aggiunto pure
il carattere \func{b} (come ultimo carattere o nel mezzo agli altri per
le stringhe di due caratteri) che in altri sistemi operativi serve a
distinguere i file binari dai file di testo; in un sistema POSIX questa
distinzione non esiste e il valore viene accettato solo per
compatibilità, ma non ha alcun effetto.

Le \acr{glibc} supportano alcune estensioni, queste devono essere sempre
indicate dopo aver specificato il \param{mode} con uno dei valori di
\tabref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
evitare di sovrascrivere un file già esistente (è analoga all'uso
dell'opzione \macro{O\_EXCL} in \func{open}), se il file specificato già
esiste e si aggiunge questo carattere a \param{mode} la \func{fopen}
fallisce. 

Un'altra estensione serve a supportare la localizzazione, quando si
aggiunge a \param{mode} una stringa della forma \verb|",ccs=STRING"| il
valore \verb|STRING| è considerato il nome di una codifica dei caratteri
e \func{fopen} marca il file per l'uso dei caratteri estesi e abilita le
opportune funzioni di conversione in lettura e scrittura.

Inoltre nel caso si usi \func{fdopen} i valori specificati da
\param{mode} devono essere compatibili con quelli con cui il file
descriptor è stato aperto. Inoltre i modi \cmd{w} e \cmd{w+} non
troncano il file. La posizione nello stream viene settata a quella
corrente nel file descriptor, e le variabili di errore e di fine del
file (vedi \secref{sec:file_io}) sono cancellate. Il file non viene
duplicato e verrà chiuso alla chiusura dello stream.

I nuovi file saranno creati secondo quanto visto in
\secref{sec:file_ownership} ed avranno i permessi di accesso settati al
valore \macro{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH}
(pari a \macro{0666}) modificato secondo il valore di \acr{umask} per il
processo (si veda \secref{sec:file_umask}).

In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di messo una bufferizzazione; per questo motivo lo standard ANSI C
richiede che ci sia una operazione di posizionamento fra una operazione
di output ed una di input o viceversa (eccetto il caso in cui l'input ha
incontrato la fine del file), altrimenti una lettura può ritornare anche
il risultato di scritture precedenti l'ultima effettuata. 

Per questo motivo è una buona pratica (e talvolta necessario) far seguire ad
una scrittura una delle funzioni \func{fflush}, \func{fseek}, \func{fsetpos} o
\func{rewind} prima di eseguire una rilettura; viceversa nel caso in cui si
voglia fare una scrittura subito dopo aver eseguito una lettura occorre prima
usare una delle funzioni \func{fseek}, \func{fsetpos} o \func{rewind}. Anche
una operazione nominalmente nulla come \func{fseek(file, 0, SEEK\_CUR)} è
sufficiente a garantire la sincronizzazione.

Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione
(si veda \secref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
alcuna operazione di I/O sul file.

Uno stream viene chiuso con la funzione \func{fclose} il cui prototipo è:
\begin{prototype}{stdio.h}{int fclose(FILE *stream)}
  Chiude lo stream \param{stream}. 
  
  \bodydesc{Restituisce 0 in caso di successo e \macro{EOF} in caso di errore,
    nel qual caso setta \var{errno} a \macro{EBADF} se il file descriptor
    indicato da \param{stream} non è valido, o uno dei valori specificati
    dalla sottostante funzione che è fallita (\func{close}, \func{write} o
    \func{fflush}).}
\end{prototype}

La funzione effettua lo scarico di tutti i dati presenti nei buffer di uscita
e scarta tutti i dati in ingresso; se era stato allocato un buffer per lo
stream questo verrà rilasciato. La funzione effettua lo scarico solo per i
dati presenti nei buffer in user space usati dalle \acr{glibc}; se si vuole
essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare
una \func{sync} (vedi \secref{sec:file_sync}).

Linux supporta, come estensione implementata dalle \acr{glibc}, anche una
altra funzione, \func{fcloseall}, che serve a chiudere tutti i file, il suo
prototipo è:
\begin{prototype}{stdio.h}{int fcloseall(void)}
  Chiude tutti gli stream. 
  
  \bodydesc{Restituisce 0 se non ci sono errori ed \macro{EOF} altrimenti.}
\end{prototype}
\noindent la funzione esegue lo scarico dei dati bufferizzati in uscita
e scarta quelli in ingresso, chiudendo tutti i file. Questa funzione è
provvista solo per i casi di emergenza, quando si è verificato un errore
ed il programma deve essere abortito, ma si vuole compiere qualche altra
operazione dopo aver chiuso i file e prima di uscire (si ricordi quanto
visto in \secref{sec:proc_exit}).


\subsection{Lettura e scrittura su uno stream}
\label{sec:file_io}

Una delle caratteristiche più utili dell'interfaccia degli stream è la
ricchezza delle funzioni disponibili per le operazioni di lettura e
scrittura sui file. Sono infatti previste ben tre diverse modalità
modalità di input/output non formattato:
\begin{enumerate*}
\item\textsl{binario} in cui legge/scrive un blocco di dati alla
  volta, vedi \secref{sec:file_binary_io}.
\item\textsl{a caratteri} in cui si legge/scrive un carattere alla
  volta (con la bufferizzazione gestita automaticamente dalla libreria),
  vedi \secref{sec:file_char_io}.
\item\textsl{di linea} in cui si legge/scrive una linea (terminata dal
  carattere di newline \verb|\n|) alla volta, vedi
  \secref{sec:file_line_io}.
\end{enumerate*}
ed inoltre la modalità di input/output formattato.

A differenza dell'interfaccia dei file descriptor, con gli stream il
raggiungimento della fine del file è considerato un errore, e viene
notificato come tale dai valori di uscita delle varie funzioni. Nella
maggior parte dei casi questo avviene con la restituzione del valore
intero (di tipo \type{int}) \macro{EOF}\footnote{la costante deve essere
  negativa, le \acr{glibc} usano -1, altre implementazioni possono avere
  valori diversi.}  definito anch'esso nell'header \func{stdlib.h}.

Dato che le funzioni dell'interfaccia degli stream sono funzioni di libreria
che si appoggiano a delle system call, esse non settano direttamente la
variabile \var{errno}, che mantiene il valore settato dalla system call che ha
riportato l'errore. 

Siccome la condizione di end-of-file è anch'essa segnalata come errore, nasce
il problema di come distinguerla da un errore effettivo; basarsi solo sul
valore di ritorno della funzione e controllare il valore di \var{errno}
infatti non basta, dato che quest'ultimo potrebbe essere stato settato in una
altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del
funzionamento di \var{errno}).

Per questo motivo tutte le implementazioni delle librerie standard
mantengono per ogni stream almeno due flag all'interno dell'oggetto
\type{FILE}, il flag di \textit{end-of-file}, che segnala che si è
raggiunta la fine del file in lettura, e quello di errore, che segnala
la presenza di un qualche errore nelle operazioni di input/output;
questi due flag possono essere riletti dalle funzioni:
\begin{functions}
  \headdecl{stdio.h}
  \funcdecl{int feof(FILE *stream)}
  Controlla il flag di end-of-file di \param{stream}.
  \funcdecl{int ferror(FILE *stream)}
  Controlla il flag di errore di \param{stream}.
  
  \bodydesc{Entrambe le funzioni ritornano un valore diverso da zero se
    i relativi flag sono settati.}
\end{functions}
\noindent si tenga presente comunque che la lettura di questi flag segnala
soltanto che c'è stato un errore, o che si è raggiunta la fine del file in una
qualunque operazione sullo stream, il controllo quindi deve essere effettuato
ogni volta che si chiama una funzione di libreria.

Entrambi i flag (di errore e di end-of-file) possono essere cancellati usando
la funzione \func{clearerr}, il cui prototipo è:
\begin{prototype}{stdio.h}{void clearerr(FILE *stream)}
  Cancella i flag di errore ed end-of-file di \param{stream}. 
\end{prototype}
\noindent in genere si usa questa funziona una volta che si sia identificata e
corretta la causa di un errore per evitare di mantenere i flag attivi,
così da poter rilevare una successiva ulteriore condizione di errore.


\subsection{Input/output binario}
\label{sec:file_binary_io}

La prima modalità di input/output non formattato ricalca quella della
interfaccia dei file descriptor, e provvede semplicemente la scrittura e
la lettura dei dati da un buffer verso un file e viceversa. In generale
questa è la modalità che si usa quando si ha a che fare con dati non
formattati. Le due funzioni che si usano per l'I/O binario sono:
\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{size\_t fread(void *ptr, size\_t size, size\_t nmemb, FILE
    *stream)}
  
  \funcdecl{size\_t fwrite(const void *ptr, size\_t size, size\_t
    nmemb, FILE *stream)}
  
  Rispettivamente leggono e scrivono \param{nmemb} elementi di dimensione
  \param{size} dal buffer \param{ptr} al file \param{stream}.
  
  \bodydesc{Entrambe le funzioni ritornano il numero di elementi letti o
    scritti, in caso di errore o fine del file viene restituito un numero di
    elementi inferiore al richiesto.}
\end{functions}

In genere si usano queste funzioni quando si devono trasferire su file
blocchi di dati binari in maniera compatta e veloce; un primo caso di uso
tipico è quello in cui si salva un vettore (o un certo numero dei suoi
elementi) con una chiamata del tipo:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
int WriteVect(FILE *stream, double *vec, size_t nelem) 
{
    int size, nread;
    size = sizeof(*vec);
    if ( (nread = fwrite(vec, size, nelem, stream)) != nelem) {
        perror("Write error");
    }
    return nread;
}
\end{lstlisting}
in questo caso devono essere specificate le dimensioni di ciascun
elemento ed il numero di quelli che si vogliono scrivere. Un secondo
caso è invece quello in cui si vuole trasferire su file una struttura;
si avrà allora una chiamata tipo:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
struct histogram {
    int nbins; 
    double max, min;
    double * bin;
} histo; 

int WriteStruct(FILE * stream, struct histogram * histo, size_t nelem) 
{
    if ( fwrite(vec, sizeof(*histo), 1, stream) !=1) {
        perror("Write error");
    }
    return nread;
}
\end{lstlisting}
in cui si specifica la dimensione dell'intera struttura ed un solo
elemento. 

In realtà quello che conta nel trasferimento dei dati sono le dimensioni
totali, che sono sempre pari al prodotto \func{size * nelem}; la sola
differenza è che le funzioni non ritornano il numero di byte scritti,
ma il numero di elementi.

La funzione \func{fread} legge sempre un numero intero di elementi, se
incontra la fine del file l'oggetto letto parzialmente viene scartato
(lo stesso avviene in caso di errore). In questo caso la posizione dello
stream viene settata alla fine del file (e non a quella corrispondente
alla quantità di dati letti).

In caso di errore (o fine del file per \func{fread}) entrambe le
funzioni restituiscono il numero di oggetti effettivamente letti o
scritti, che sarà inferiore a quello richiesto. Contrariamente a quanto
avviene per i file descriptor, questo segnala una condizione di errore e
occorrerà usare \func{feof} e \func{ferror} per stabilire la natura del
problema.

Benché queste funzioni assicurino la massima efficienza per il
salvataggio dei dati, i dati memorizzati attraverso di esse presentano
lo svantaggio di dipendere strettamente dalla piattaforma di sviluppo
usata ed in genere possono essere riletti senza problemi solo dallo
stesso programma che li ha prodotti.

Infatti diversi compilatori possono eseguire ottimizzazioni diverse
delle strutture dati e alcuni compilatori (come il \cmd{gcc}) possono
anche scegliere se ottimizzare l'occupazione di spazio, impacchettando
più strettamente i dati, o la velocità inserendo opportuni
\textit{padding} per l'allineamento dei medesimi generando quindi output
binari diversi. Inoltre altre incompatibilità si possono presentare
quando entrano in gioco differenze di architettura hardware, come la
dimensione del bus o la modalità di ordinamento dei bit o il formato
delle variabili in floating point.

Per questo motivo quando si usa l'input/output binario occorre sempre
essere prendere le opportune precauzioni (in genere usare un formato di
più alto livello che permetta di recuperare l'informazione completa),
per assicurarsi che versioni diverse del programma siano in grado di
rileggere i dati tenendo conto delle eventuali differenze.

Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, che
evitano il lock implicito dello stream, usato per dalla librerie per la
gestione delle applicazioni multi-thread (si veda
\secref{sec:file_stream_thread} per i dettagli).

\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{size\_t fread\_unlocked(void *ptr, size\_t size, size\_t
    nmemb, FILE *stream)}
  
  \funcdecl{size\_t fwrite\_unlocked(const void *ptr, size\_t size,
    size\_t nmemb, FILE *stream)}
  
  \bodydesc{Le funzioni sono identiche alle analoghe \func{fread} e
    \func{fwrite} ma non acquisiscono il lock implicito sullo stream.}
\end{functions}
\noindent entrambe le funzioni sono estensioni GNU previste solo dalle
\acr{glibc}.


\subsection{Input/output a caratteri}
\label{sec:file_char_io}

La seconda modalità di input/output è quella a caratteri, in cui si
trasferisce un carattere alla volta.  Le funzioni per la lettura a
caratteri sono tre, \func{fgetc}, \func{getc} e \func{getchar}, i
rispettivi prototipi sono:
\begin{functions}
  \headdecl{stdio.h} 

  \funcdecl{int getc(FILE *stream)} Legge un byte da \param{stream} e lo
  restituisce come intero. In genere è implementata come una macro. 

  \funcdecl{int fgetc(FILE *stream)} Legge un byte da \param{stream} e lo
  restituisce come intero. È una sempre una funzione.
  
  \funcdecl{int getchar(void)} Equivalente a \func{getc(stdin)}.
  
  \bodydesc{Tutte queste funzioni leggono un byte alla volta, che viene
    restituito come intero; in caso di errore o fine del file il valore
    di ritorno è \macro{EOF}.}
\end{functions}

A parte \func{getchar}, che si usa in genere per leggere un carattere da
tastiera, le altre due funzioni sono sostanzialmente equivalenti. La
differenza è che \func{gets} è ottimizzata al massimo e normalmente
viene implementata con una macro, per cui occorre stare attenti a cosa
le si passa come argomento, infatti \param{stream} può essere valutato
più volte nell'esecuzione, e non viene passato in copia con il
meccanismo visto in \secref{sec:proc_var_passing}; per questo motivo se
si passa una espressione si possono avere effetti indesiderati.

Invece \func{fgets} è assicurata essere sempre una funzione, per questo
motivo la sua esecuzione normalmente è più lenta per via dell'overhead
della chiamata, ma è altresì possibile ricavarne l'indirizzo, che può
essere passato come parametro ad un altra funzione (e non si hanno i
problemi accennati in precedenza con \param{stream}).

Le tre funzioni restituiscono tutte un \type{unsigned char} convertito
ad \type{int} (si usa \type{unsigned char} in modo da evitare
l'espansione del segno). In questo modo il valore di ritorno è sempre
positivo, tranne in caso di errore o fine del file.

Nelle estensioni GNU che provvedono la localizzazione sono definite tre
funzioni equivalenti alle precedenti che invece di un carattere di un
byte restituiscono un carattere in formato esteso (cioè di tipo
\type{wint\_t}, il loro prototipo è:
\begin{functions}
  \headdecl{stdio.h} 
  \headdecl{wchar.h} 
  
  \funcdecl{wint\_t getwc(FILE *stream)} Legge un carattere esteso da
  \param{stream}. In genere è implementata come una macro.
  
  \funcdecl{wint\_t fgetwc(FILE *stream)} Legge un carattere esteso da
  \param{stream} È una sempre una funzione.
  
  \funcdecl{wint\_t getwchar(void)} Equivalente a \func{getwc(stdin)}.
  
  \bodydesc{Tutte queste funzioni leggono un carattere alla volta, in
    caso di errore o fine del file il valore di ritorno è \macro{WEOF}.}
\end{functions}

Per scrivere un carattere si possono usare tre funzioni analoghe alle
precedenti usate per leggere: \func{putc}, \func{fputc} e
\func{putchar}; i loro prototipi sono:
\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{int putc(int c, FILE *stream)} Scrive il carattere \param{c}
  su \param{stream}. In genere è implementata come una macro.
  
  \funcdecl{int fputc(FILE *stream)} Scrive il carattere \param{c} su
  \param{stream}. È una sempre una funzione.
  
  \funcdecl{int putchar(void)} Equivalente a \func{putc(stdin)}.
  
  \bodydesc{Le funzioni scrivono sempre un carattere alla volta, il cui
    valore viene restituito in caso di successo; in caso di errore o
    fine del file il valore di ritorno è \macro{EOF}.}
\end{functions}

Tutte queste funzioni scrivono sempre un byte alla volta, anche se
prendono come parametro un \type{int} (che pertanto deve essere ottenuto
con un cast da un \type{unsigned char}). Anche il valore di ritorno è
sempre un intero; in caso di errore o fine del file il valore di ritorno
è \macro{EOF}.

Come nel caso dell'I/O binario le \acr{glibc} provvedono per ciascuna
delle funzioni precedenti, come estensione GNU, una seconda funzione, il
cui nome è ottenuto aggiungendo un \func{\_unlocked}, che esegue
esattamente le stesse operazioni evitando però il lock implicito dello
stream.

Per compatibilità con SVID sono provviste anche due funzioni per leggere
e scrivere una \textit{word} (che è sempre definita come \type{int}); i
loro prototipi sono:
\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{int getw(FILE *stream)} Legge una parola da \param{stream}.
  \funcdecl{int putw(int w, FILE *stream)} Scrive la parola \param{w} su
  \param{stream}.
  
  \bodydesc{Le funzioni restituiscono la parola \param{w}, o \macro{EOF}
    in caso di errore o di fine del file.}
\end{functions}
\noindent l'uso di queste funzioni è deprecato in favore dell'uso di
\func{fread} e \func{fwrite}, in quanto non è possibile distinguere il
valore -1 da una condizione di errore che restituisce \macro{EOF}.

Una degli usi più frequenti dell'input/output a caratteri è nei
programmi di \textit{parsing} in cui si analizza il testo; in questo
contesto diventa utile poter analizzare il carattere successivo da uno
stream senza estrarlo effettivamente (la tecnica è detta \textit{peeking
  ahead}) in modo che il programma possa regolarsi sulla base avendo
dato una \textsl{sbirciatina} a quello che viene dopo. 

Nel nostro caso questo tipo di comportamento può essere realizzato prima
leggendo il carattere, e poi rimandandolo indietro, cosicché ridiventi
disponibile per una lettura successiva; la funzione che inverte la
lettura si chiama \func{ungetc} ed il suo prototipo è:
\begin{prototype}{stdio.h}{int ungetc(int c, FILE *stream)}
  Rimanda indietro il carattere \param{c}, con un cast a \type{unsigned
    char}, sullo stream \param{stream}.

  \bodydesc{La funzione ritorna \param{c} in caso di successo e
  \macro{EOF} in caso di errore.}
\end{prototype}
\noindent benché lo standard ANSI C preveda che l'operazione possa
essere ripetuta per un numero arbitrario di caratteri, alle
implementazioni è richiesto di garantire solo un livello; questo è
quello che fa la \acr{glibc}, che richiede che avvenga un'altra
operazione fra due \func{ungetc} successive.

Non è necessario che il carattere che si manda indietro sia l'ultimo che
si è letto, e non è necessario neanche avere letto nessun carattere
prima di usare \func{ungetc}, ma di norma la funzione è intesa per
essere usata per rimandare indietro l'ultimo carattere letto.

Nel caso \param{c} sia un \macro{EOF} la funzione non fa nulla, e
restituisce sempre \macro{EOF}; così si può usare \func{ungetc} anche
con il risultato di una lettura alla fine del file.

Se si è alla fine del file si può comunque rimandare indietro un
carattere, il flag di end-of-file verrà automaticamente cancellato
perché c'è un nuovo carattere disponibile che potrà essere riletto
successivamente.

Infine si tenga presente che \func{ungetc} non altera il contenuto del
file, ma opera esclusivamente sul buffer interno. Se si esegue una
qualunque delle operazioni di riposizionamento (vedi
\secref{sec:file_fseek}) i caratteri rimandati indietro vengono
scartati.


\subsection{Input/output di linea}
\label{sec:file_line_io}

La terza ed ultima modalità di input/output non formattato è quella di
linea, in cui legge o scrive una riga alla volta; questa è una modalità
molto usata per l'I/O da terminale, ma che presenta le caratteristiche
più controverse.

Le funzioni previste dallo standard ANSI C per leggere una linea sono
sostanzialmente due, \func{gets} e \func{fgets}, i cui rispettivi
prototipi sono:
\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{char *gets(char *string)} Scrive su \param{string} una
  linea letta da \var{stdin}.
  
  \funcdecl{char *fgets(char *string, int size, FILE *stream)}
  Scrive su \param{string} la linea letta da \param{stream} per un
  massimo di \param{size} byte.
  
  \bodydesc{Le funzioni restituiscono l'indirizzo \param{string} in caso
    di successo o \macro{NULL} in caso di errore.}
\end{functions}

Entrambe le funzioni effettuano la lettura (dal file specificato
\func{fgets}, dallo standard input \func{gets}) di una linea di
caratteri (terminata dal carattere \textit{newline}, \verb|\n|), ma
\func{gets} sostituisce \verb|\n| con uno zero, mentre \func{fgets}
aggiunge uno zero dopo il \textit{newline}, che resta dentro la
stringa. Se la lettura incontra la fine del file (o c'è un errore) viene
restituito un \macro{NULL}, ed il buffer \param{buf} non viene toccato.

L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la
funzione infatti non controlla il numero di byte letti, per cui nel caso
la stringa letta superi le dimensioni del buffer, si avrà un
\textit{buffer overflow}, con sovrascrittura della memoria del processo
adiacente al buffer. 

Questa è una delle vulnerabilità più sfruttate per guadagnare accessi
non autorizzati al sistema (i cosiddetti \textit{exploit}), basta
infatti inviare una stringa sufficientemente lunga ed opportunamente
forgiata per sovrascrivere gli indirizzi di ritorno nello stack
(supposto che la \func{gets} sia stata chiamata da una subroutine), in
modo da far ripartire l'esecuzione nel codice inviato nella stringa
stessa (in genere uno \textit{shell code} cioè una sezione di programma
lancia una shell).

La funzione \func{fgets} non ha i precedenti problemi di \func{gets} in
quanto prende in input la dimensione del buffer \param{size}, che non
verrà mai ecceduta in lettura. La funzione legge fino ad un massimo di
\param{size} caratteri (newline compreso), ed aggiunge uno zero di
terminazione; questo comporta che la stringa possa essere al massimo di
\var{size-1} caratteri.  Se la linea eccede la dimensione del buffer
verranno letti solo \var{size-1} caratteri, ma la stringa sarà sempre
terminata correttamente con uno zero finale; sarà possibile leggere i
restanti caratteri in una chiamata successiva.

Per la scrittura di una linea lo standard ANSI C prevede altre due
funzioni, \func{fputs} e \func{puts}, analoghe a quelle di lettura, i
rispettivi prototipi sono:
\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{int puts(const char *string)} Scrive su \var{stdout} la
  linea \param{string}.
  
  \funcdecl{int fputs(const char *string, FILE *stream)} Scrive su
  \param{stream} la linea \param{string}.
  
  \bodydesc{Le funzioni restituiscono un valore non negativo in caso di
    successo o \macro{EOF} in caso di errore.}
\end{functions}

Dato che in questo caso si scrivono i dati in uscita \func{puts} non ha
i problemi di \func{gets} ed è in genere la forma più immediata per
scrivere messaggi sullo standard output; la funzione prende una stringa
terminata da uno zero ed aggiunge automaticamente un newline. La
differenza con \func{fputs} (a parte la possibilità di specificare un
file diverso da \var{stdout}) è che quest'ultima non aggiunge il
newline, che deve essere previsto esplicitamente. 

Come per le funzioni di input/output a caratteri esistono le estensioni
per leggere e scrivere caratteri estesi, i loro prototipi sono:
\begin{functions}
  \headdecl{wchar.h} 
  \funcdecl{wchar\_t *fgetws(wchar\_t *ws, int n, FILE *stream)}
  Legge un massimo di \param{n} caratteri estesi dal file
  \param{stream} al buffer \param{ws}.
  
  \funcdecl{int fputws(const wchar\_t *ws, FILE *stream)} Scrive la
  linea \param{ws} di caratteri estesi sul file \param{stream}.
  
  \bodydesc{Le funzioni ritornano rispettivamente \param{ws} o un numero
    non negativo in caso di successo e \macro{NULL} o \macro{EOF} in
    caso di errore o fine del file.}
\end{functions}
\noindent il comportamento è identico a quello di \func{fgets} e
\func{fputs} solo che tutto (numero di caratteri massimo, terminatore
della stringa, newline) è espresso in termini di caratteri estesi
anziché di caratteri ASCII.

Come nel caso dell'I/O binario e a caratteri nelle \acr{glibc} sono
previste una serie di altre funzioni, estensione di tutte quelle
illustrate finora (eccetto \func{gets} e \func{puts}), il cui nome si
ottiene aggiungendo un \func{\_unlocked}, e che eseguono esattamente le
stesse operazioni delle loro equivalenti, evitando però il lock
implicito dello stream (vedi \secref{sec:file_stream_thread}).

Come abbiamo visto, le funzioni di lettura per l'input/output di linea
previste dallo standard ANSI C presentano svariati inconvenienti. Benché
\func{fgets} non abbia i gravissimi problemi di \func{gets}, può
comunque dare risultati ambigui se l'input contiene degli zeri; questi
infatti saranno scritti sul buffer di uscita e la stringa in output
apparirà come più corta dei byte effettivamente letti. Questa è una
condizione che è sempre possibile controllare (deve essere presente un
newline prima della effettiva conclusione della stringa presente nel
buffer), ma a costo di una complicazione ulteriore della logica del
programma. Lo stesso dicasi quando si deve gestire il caso di stringa
che eccede le dimensioni del buffer.

Per questo motivo le \acr{glibc} prevedono, come estensione GNU, due
nuove funzioni per la gestione dell'input/output di linea, il cui uso
permette di risolvere questi problemi. L'uso di queste funzioni deve
essere attivato definendo la macro \macro{\_GNU\_SOURCE} prima di
includere \file{stdio.h}. La prima delle due, \func{getline}, serve per
leggere una linea terminata da un newline esattamente allo stesso modo
di \func{fgets}, il suo prototipo è:
\begin{prototype}{stdio.h}
  {ssize\_t getline(char **buffer, size\_t *n, FILE *stream)} Legge una
  linea dal file \param{stream} sul buffer indicato da \param{buffer}
  riallocandolo se necessario (l'indirizzo del buffer e la sua
  dimensione vengono sempre riscritte).

  \bodydesc{La funzione ritorna il numero di caratteri letti in caso di
  successo e -1 in caso di errore o di raggiungimento della fine del
  file.}
\end{prototype}

La funzione permette di eseguire una lettura senza doversi preoccupare
della eventuale lunghezza eccessiva della stringa da leggere. Essa
prende come primo parametro l'indirizzo del puntatore al buffer su cui
si vuole leggere la linea. Quest'ultimo \emph{deve} essere stato
allocato in precedenza con una \func{malloc} (non si può passare
l'indirizzo di un puntatore ad una variabile locale); come secondo
parametro la funzione vuole l'indirizzo della variabile contenente le
dimensioni del buffer suddetto.

Se il buffer di destinazione è sufficientemente ampio la stringa viene
scritta subito, altrimenti il buffer viene allargato usando
\func{realloc} e la nuova dimensione ed il nuovo puntatore vengono
passata indietro (si noti infatti come per entrambi i parametri si siano
usati dei \textit{value result argument}, passando dei puntatori anzichè
i valori delle variabili, secondo la tecnica spiegata in
\secref{sec:proc_var_passing}).

Se si passa alla funzione l'indirizzo ad un puntatore settato a
\macro{NULL} e \var{*n} è zero, la funzione provvede da sola
all'allocazione della memoria necessaria a contenere la linea. In tutti
i casi si ottiene dalla funzione un puntatore all'inizio del testo della
linea. Un esempio di codice può essere il seguente:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
    size_t n = 0; 
    char *ptr = NULL;
    int nread;
    FILE * file;
    ...    
    nread = getline(&ptr, &n, file);
\end{lstlisting}
e per evitare memory leak occorre ricordarsi di liberare \var{ptr} con
una \func{free}.

Il valore di ritorno della funzione indica il numero di caratteri letti
dallo stream (quindi compreso il newline, ma non lo zero di
terminazione); questo permette anche di distinguere eventuali zeri letti
dallo stream da quello inserito dalla funzione per terminare la linea.
Se si è alla fine del file e non si è potuto leggere nulla o c'è stato
un errore la funzione restituisce -1.

La seconda estensione GNU è una generalizzazione di \func{getline} per
poter usare come separatore un carattere qualsiasi, la funzione si
chiama \func{getdelim} ed il suo prototipo è:
\begin{prototype}{stdio.h}
{ssize\_t getdelim(char **buffer, size\_t *n, int delim, FILE *stream)} 
  Identica a \func{getline} solo che usa \param{delim} al posto del
  carattere di newline come separatore di linea.
\end{prototype}

Il comportamento di \func{getdelim} è identico a quello di
\func{getline} (che può essere implementata da questa passando
\verb|'\n'| come valore di \param{delim}).


\subsection{Input/output formattato}
\label{sec:file_formatted_io}

L'ultima modalità di input/output è quella formattata, che è una delle
caratteristiche più utilizzate delle librerie standard del C; in genere
questa è la modalità in cui si esegue normalmente l'output su terminale
poichè permette di stampare in maniera facile e veloce dati, tabelle e
messaggi.

L'output formattato viene eseguito con una delle 13 funzioni della
famiglia \func{printf}; le tre più usate sono le seguenti:
\begin{functions}
  \headdecl{stdio.h} 
  \funcdecl{int printf(const char *format, ...)} Stampa su \var{stdout}
  gli argomenti, secondo il formato specificato da \param{format}.
  
  \funcdecl{int fprintf(FILE *stream, const char *format, ...)}  Stampa
  su \param{stream} gli argomenti, secondo il formato specificato da
  \param{format}.
  
  \funcdecl{int sprintf(char *str, const char *format, ...)} Stampa
  sulla stringa \param{str} gli argomenti, secondo il formato
  specificato da \param{format}.

  \bodydesc{Le funzioni ritornano il numero di caratteri stampati.}
\end{functions}
\noindent le prime due servono per stampare su file (lo standard output
o quello specificato) la terza permette di stampare su una stringa, in
genere l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se
non si ha la sicurezza assoluta sulle dimensioni del risultato della
stampa, eccedere le dimensioni di \param{str}; per questo motivo si
consiglia l'uso dell'alternativa:
\begin{prototype}{stdio.h}
{snprintf(char *str, size\_t size, const char *format, ...);} 
  Identica a \func{sprintf}, ma non scrive su \param{str} più di
  \param{size} caratteri.
\end{prototype}

La parte più complessa di queste funzioni è il formato della stringa
\param{format} che indica le conversioni da fare, da cui poi deriva il numero
dei parametri che dovranno essere passati a seguire. La stringa è costituita
da caratteri normali (tutti eccetto \texttt{\%}), che vengono passati
invariati all'output, e da direttive di conversione, in cui devono essere
sempre presenti il carattere \texttt{\%}, che introduce la direttiva, ed uno
degli specificatori di conversione (riportati in \ntab) che la conclude. 

\begin{table}[htb]
  \centering
  \begin{tabular}[c]{|l|l|p{10cm}|}
    \hline
    \textbf{Valore} & \textbf{Tipo} & \textbf{Significato} \\
    \hline
    \hline
   \cmd{\%d} &\type{int}         & Stampa un numero intero in formato decimale
                                   con segno \\
   \cmd{\%i} &\type{int}         & Identico a \cmd{\%i} in output, \\
   \cmd{\%o} &\type{unsigned int}& Stampa un numero intero come ottale\\
   \cmd{\%u} &\type{unsigned int}& Stampa un numero intero in formato
                                   decimale senza segno \\
   \cmd{\%x}, 
   \cmd{\%X} &\type{unsigned int}& Stampano un intero in formato esadecimale,
                                   rispettivamente con lettere minuscole e
                                   maiuscole. \\
   \cmd{\%f} &\type{unsigned int}& Stampa un numero in virgola mobile con la
                                   notazione a virgola fissa \\
   \cmd{\%e}, 
   \cmd{\%E} &\type{double} & Stampano un numero in virgola mobile con la
                              notazione esponenziale, rispettivamente con
                              lettere minuscole e maiuscole. \\
   \cmd{\%g}, 
   \cmd{\%G} &\type{double} & Stampano un numero in virgola mobile con la
                              notazione più appropriate delle due precedenti,
                              rispettivamente con lettere minuscole e
                              maiuscole. \\
   \cmd{\%a}, 
   \cmd{\%A} &\type{double} & Stampano un numero in virgola mobile in
                              notazione esadecimale frazionaria\\
   \cmd{\%c} &\type{int}    & Stampa un carattere singolo\\
   \cmd{\%s} &\type{char *} & Stampa una stringa \\
   \cmd{\%p} &\type{void *} & Stampa il valore di un puntatore\\
   \cmd{\%n} &\type{\&int}  & Prende il numero di caratteri stampati finora\\
   \cmd{\%\%}&              & Stampa un \% \\
    \hline
  \end{tabular}
  \caption{Valori possibili per gli specificatori di conversione in una
    stringa di formato di \func{printf}.} 
  \label{tab:file_format_spec}
\end{table}


Il formato di una direttiva di conversione prevede una serie di possibili
elementi opzionali oltre al \cmd{\%} e allo specificatore di conversione; in
generale essa è sempre del tipo:
\begin{center}
\begin{verbatim}
% [n. parametro $] [flag] [[larghezza] [. precisione]] [tipo] conversione
\end{verbatim}
\end{center}
in cui i valori opzionali sono indicati fra parentesi, e prevedono la
presenza, in questo ordine, di: uno specificatore per il parametro da usare
(terminato da un \cmd{\$}, uno o più flag (riassunti in
\tabref{tab:file_format_flag}) che controllano il formato di stampa della
conversione (riassunti in \tabref{tab:file_format_type}), uno specificatore di
larghezza, eventualmente seguito (per i numeri in virgola mobile) da un
specificatore di precisione, uno specificatore del tipo di dato (che ne indica
la lunghezza).

\begin{table}[htb]
  \centering
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Valore} & \textbf{Significato}\\
    \hline
    \hline
    \cmd{\#}  & \\
    \cmd{0}   & \\
    \cmd{-}   & \\
    \cmd{' '} & \\
    \cmd{+}   & \\
    \hline
  \end{tabular}
  \caption{I valori dei flag per il formato di \func{printf}}
  \label{tab:file_format_flag}
\end{table}



\begin{table}[htb]
  \centering
  \begin{tabular}[c]{|l|p{10cm}|}
    \hline
    \textbf{Valore} & \textbf{Significato} \\
    \hline
    \hline
    \cmd{hh} & \\
    \cmd{h}  & \\
    \cmd{l}  & \\
    \cmd{ll} & \\
    \cmd{L}  & \\
    \cmd{q}  & \\
    \cmd{j}  & \\
    \cmd{z}  & \\
    \cmd{t}  & \\
    \hline
  \end{tabular}
  \caption{Il modificatore di tipo di dato per il formato di \func{printf}}
  \label{tab:file_format_type}
\end{table}





\subsection{Posizionamento su uno stream}
\label{sec:file_fseek}

Come per i file descriptor è possibile anche con gli stream spostarsi
all'interno di un file per effettuare operazioni di lettura o scrittura in un
punto prestabilito; questo fintanto che l'operazione di riposizionamento è
supportata dal file sottostante lo stream, quando cioè si ha a che fare con
quello che viene detto un file ad \textsl{accesso casuale}.

In GNU/Linux ed in generale in ogni sistema unix-like la posizione nel
file è espressa da un intero positivo, rappresentato dal tipo
\type{off\_t}, il problema è alcune delle funzioni usate per il
riposizionamento sugli stream originano dalle prime versioni di unix in
cui questo tipo non era ancora stato definito, e che in altri sistemi
non è detto che la posizione su un file venga sempre rappresentata con
un numero di caratteri (ad esempio in VMS può essere rappresentata come
numero di record, e offset rispetto al record corrente).

Tutto questo comporta la presenza di diverse funzioni che eseguono
sostanzialmente le stesse operazioni, ma usano parametri di tipo
diverso. Le funzioni tradizionali usate per il riposizionamento della
posizione in uno stream sono:
\begin{functions}
  \headdecl{stdio.h} 
  
  \funcdecl{int fseek(FILE *stream, long offset, int whence)} Sposta la
  posizione nello stream secondo quanto specificato tramite \param{offset}
  e \param{whence}.  

  \funcdecl{void rewind(FILE *stream)} Riporta la posizione nello stream
  all'inizio del file.
\end{functions}

L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i
file descriptor, ed i parametri, a parte il tipo, hanno lo stesso
significato; in particolare \param{whence} assume gli stessi valori già
visti in \secref{sec:file_lseek}. La funzione restituisce 0 in caso di
successo e -1 in caso di errore. 

Per leggere la posizione corrente si usa invece la funzione \func{ftell}, il
cui prototipo è:
\begin{prototype}{stdio.h}{long ftell(FILE *stream)} 
  Legge la posizione attuale nello stream.
  
  \bodydesc{La funzione restituisce la posizione corrente, o -1 in caso
    di fallimento, che può esser dovuto sia al fatto che il file non
    supporta il riposizionamento che al fatto che la posizione non può
    essere espressa con un \type{long int}}
\end{prototype}

  


\section{Funzioni avanzate}
\label{sec:file_stream_adv_func}

In questa sezione esamineremo le funzioni che permettono di controllare
alcune caratteristiche più particolari degli stream, come la lettura
degli attributi, le modalità di bufferizzazione, etc.


\subsection{Le funzioni di controllo}
\label{sec:file_stream_cntrl}

Al contrario di quanto avviene con i file descriptor le librerie standard del
C non prevedono nessuna funzione come la \func{fcntl} per la lettura degli
attributi degli stream; le \acr{glibc} però supportano alcune estensioni
derivate da Solaris, che permettono di ottenere informazioni utili.

In certi casi può essere necessario sapere se un certo stream è accessibile in
lettura o scrittura. In genere questa informazione non è disponibile, e si
deve ricordare come il file è stato aperto. La cosa può essere complessa se le
operazioni vengono effettuate in una subroutine, che a questo punto
necessiterà di informazioni aggiuntive rispetto al semplice puntatore allo
stream; questo può essere evitato con le due funzioni \func{\_\_freadable} e
\func{\_\_fwritable} i cui prototipi sono:
\begin{functions}
  \headdecl{stdio\_ext.h}
  \funcdecl{int \_\_freadable (FILE *stream)}
  Restituisce un valore diverso da zero se \param{stream} consente la lettura.

  \funcdecl{int \_\_fwritable(FILE *stream)}  
  Restituisce un valore diverso da zero se \param{stream} consente la
  scrittura.
\end{functions}

Altre due funzioni, \func{\_\_freading} e \func{\_\_fwriting} servono ad un
uso ancora più specialistico, il loro prototipo è: 
\begin{functions}
  \headdecl{stdio\_ext.h}
  \funcdecl{int \_\_freading (FILE *stream)}
  Restituisce un valore diverso da zero se \param{stream} è aperto in sola
  lettura o se l'ultima operazione è stata di lettura.

  \funcdecl{int \_\_fwriting(FILE *stream)}  
  Restituisce un valore diverso da zero se \param{stream} è aperto in sola
  scrittura o se l'ultima operazione è stata di scrittura.
\end{functions}

Le due funzioni hanno lo scopo di determinare di che tipo è stata l'ultima
operazione eseguita su uno stream aperto in lettura/scrittura; ovviamente se
uno stream è aperto in sola lettura (o sola scrittura) la modalità dell'ultima
operazione è sempre determinata; l'unica ambiguità è quando non sono state
ancora eseguite operazioni, in questo caso le funzioni rispondono come se
una operazione ci fosse comunque stata.

La conoscenza dell'ultima operazione effettuata su uno stream aperto in
lettura/scrittura è utile in quanto permette di trarre conclusioni sullo stato
del buffer e del suo contenuto.


\subsection{Il controllo della bufferizzazione}
\label{sec:file_buffering_ctrl}

Come accennato in \secref{sec:file_buffering} le librerie definiscono una
serie di funzioni che permettono di controllare il comportamento degli
stream; se non si è 


\subsection{Gli stream e i thread}
\label{sec:file_stream_thread}

Gli stream possono essere usati in applicazioni multi-thread allo stesso
modo in cui sono usati nelle applicazioni normali, ma si deve essere
consapevoli delle possibili complicazioni anche quando non si usano i
thread, dato che l'implementazione delle librerie è influenzata
pesantemente dalle richieste necessarie per garantirne l'uso coi thread.



\begin{functions}
  \headdecl{stdio.h}
  
  \funcdecl{void flockfile(FILE *stream)} Esegue l'acquisizione del
  lock dello stream \param{stream}, bloccandosi in caso il lock non
  disponibile. 
  
  \funcdecl{int ftrylockfile(FILE *stream)} Tenta l'acquisizione del
  lock dello stream \param{stream}, senza bloccarsi in caso il lock non sia
  disponibile. Ritorna zero in caso di acquisizione del lock, diverso da
  zero altrimenti.
  
  \funcdecl{void funlockfile(FILE *stream)} Rilascia il lock dello
  stream \param{stream}.
\end{functions}


\subsection{Dettagli dell'implementazione}
\label{sec:file_stream_details}


\subsection{File temporanei}
\label{sec:file_temp_file}


\subsection{Efficienza}
\label{sec:file_stream_efficiency}

