\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:
+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.
+\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:
+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 possono essere definite come macro, se si hanno problemi
-di portabilità e si vuole essere sicuri, diventa opportuno usare la funzione
-\func{freopen}.
+ma in altri sistemi possono essere definite come macro, 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}, dall'inglese
-\textit{flush}, dei dati) 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:
+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.
+\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}.
+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
elementi inferiore al richiesto.
\end{functions}
-In genere si usano queste funzioni quando si devono leggere o scrivere
-un array o una struttura; un tipico esempio è quello in cui si salva una
-parte di un vettore con una chiamata del tipo:
+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)
{
return nread;
}
\end{lstlisting}
-nel qual caso devono essere specificate dimensione e numero degli
-elementi del vettore; nel caso di una struttura invece si avrà un
-qualcosa tipo:
+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) {
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 bytes
+scritti, ma il numero di elementi.
+
+La funzione \func{fread} legge sempre un numero intero di elementi, se
+si ha un errore o si incontra la fine del file l'oggetto letto
+parzialmente viene scartato
+Benché queste funzioni assicurino
\subsection{Input/output a caratteri singoli}