%% filestd.tex
%%
-%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2010 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
-%% Free Software Foundation; with the Invariant Sections being "Prefazione",
+%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{I file: l'interfaccia standard ANSI C}
\label{cha:files_std_interface}
\section{Introduzione}
\label{sec:file_stream_intro}
-Come visto in \capref{cha:file_unix_interface} le operazioni di I/O sui file
+Come visto in cap.~\ref{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.
\label{sec:file_stream}
\index{file!stream|(}
+
Come più volte ribadito, l'interfaccia dei file descriptor è un'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 \cite{APUE} Stevens descrive una serie di test sull'influenza delle
-dimensioni del blocco di dati (il parametro \param{buf} di \func{read} e
+dimensioni del blocco di dati (l'argomento \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
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.
+sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in
+sez.~\ref{sec:file_access_control} per il controllo di accesso.
+
\index{file!stream|)}
-\subsection{Gli oggetti \ctyp{FILE}}
+\subsection{Gli oggetti \type{FILE}}
\label{sec:file_FILE}
+
Per ragioni storiche la struttura di dati che rappresenta uno stream è stata
-chiamata \ctyp{FILE}, questi oggetti sono creati dalle funzioni di libreria e
+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 (che sono dei \textsl{tipi opachi}\index{tipo!opaco}) ma
-usare sempre puntatori del tipo \ctyp{FILE *} ottenuti dalla libreria stessa
+queste strutture (che sono dei \index{tipo!opaco} \textsl{tipi opachi}) ma
+usare sempre puntatori del tipo \texttt{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
+come argomenti 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})
+Ai tre file descriptor standard (vedi sez.~\ref{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
sullo schermo.
\end{basedescript}
-Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono
-effettivamente tre variabili di tipo \ctyp{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}.
+Nelle \acr{glibc} \var{stdin}, \var{stdout} e \var{stderr} sono effettivamente
+tre variabili di tipo \type{FILE}\texttt{ *} che possono essere usate come
+tutte le altre, ad esempio si può effettuare una redirezione dell'output di un
+programma con il semplice codice: \includecodesnip{listati/redir_stdout.c} 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}
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
+In sez.~\ref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
opportune funzioni per controllare le modalità di bufferizzazione e lo scarico
dei dati.
\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
+analoghe a quelle di sez.~\ref{sec:file_base_func} per i file descriptor. In
particolare vedremo come aprire, leggere, scrivere e cambiare la posizione
corrente in uno stream.
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
+valori indicati in tab.~\ref{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
+standard (vedi sez.~\ref{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\index{socket}, che non
-possono essere aperti con le funzioni delle librerie standard del C.
+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
\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. \\
+ 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.\\
+ 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. \\
+ \itindex{append~mode} \textit{append mode}, l'accesso viene
+ posto in sola scrittura.\\
+ \texttt{a+}& Il file viene aperto (o creato se non esiste) in
+ \itindex{append~mode} \textit{append mode}, l'accesso viene
+ posto in lettura e scrittura.\\
\hline
- \texttt{b} & specifica che il file è binario, non ha alcun effetto. \\
- \texttt{x} & l'apertura fallisce se il file esiste già. \\
+ \texttt{b} & Specifica che il file è binario, non ha alcun effetto. \\
+ \texttt{x} & L'apertura fallisce se il file esiste già. \\
\hline
\end{tabular}
\caption{Modalità di apertura di uno stream dello standard ANSI C che
\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
+diversi per \param{mode}, ma in tab.~\ref{tab:file_fopen_mode} si sono
riportati solo i sei valori effettivi, ad essi può essere aggiunto pure
il carattere \texttt{b} (come ultimo carattere o nel mezzo agli altri per
le stringhe di due caratteri) che in altri sistemi operativi serve a
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
+tab.~\ref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
evitare di sovrascrivere un file già esistente (è analoga all'uso
dell'opzione \const{O\_EXCL} in \func{open}), se il file specificato già
esiste e si aggiunge questo carattere a \param{mode} la \func{fopen}
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 impostata 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.
+stream viene impostata a quella corrente nel file descriptor, e le variabili
+di errore e di fine del file (vedi sez.~\ref{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 impostati al
-valore \code{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH} (pari a
-\val{0666}) modificato secondo il valore di \acr{umask} per il processo (si
-veda \secref{sec:file_umask}).
+sez.~\ref{sec:file_ownership_management} ed avranno i permessi di accesso
+impostati al valore
+\code{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH} (pari a
+\val{0666}) modificato secondo il valore di \itindex{umask} \textit{umask} per
+il processo (si veda sez.~\ref{sec:file_perm_management}).
In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di mezzo una bufferizzazione; per questo motivo lo standard ANSI C
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
+(si veda sez.~\ref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
alcuna operazione di I/O sul file.
Uno stream viene chiuso con la funzione \funcd{fclose} il cui prototipo è:
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}).
+una \func{sync} (vedi sez.~\ref{sec:file_sync}).
Linux supporta anche una altra funzione, \funcd{fcloseall}, come estensione
GNU implementata dalle \acr{glibc}, accessibile avendo definito
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}).
+visto in sez.~\ref{sec:proc_exit}).
\subsection{Lettura e scrittura su uno stream}
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}.
+ volta, vedi sez.~\ref{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}.
+ vedi sez.~\ref{sec:file_char_io}.
\item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata
- dal carattere di newline \verb|'\n'|), vedi \secref{sec:file_line_io}.
+ dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}.
\end{enumerate*}
ed inoltre la modalità di input/output formattato.
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 impostato in
-una altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del
+una altra occasione, (si veda sez.~\ref{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
-\ctyp{FILE}, il flag di \textit{end-of-file}, che segnala che si è
+\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 \funcd{feof} e
corretta la causa di un errore per evitare di mantenere i flag attivi, così da
poter rilevare una successiva ulteriore condizione di errore. Di questa
funzione esiste una analoga \func{clearerr\_unlocked} che non esegue il blocco
-dello stream (vedi \secref{sec:file_stream_thread}).
+dello stream (vedi sez.~\ref{sec:file_stream_thread}).
\subsection{Input/output binario}
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:
-%\footnotesize
-\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}
-%\normalsize
+\includecodesnip{listati/WriteVect.c}
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:
-%\footnotesize
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-struct histogram {
- int nbins;
- double max, min;
- double *bin;
-} histo;
-
-int WriteStruct(FILE *stream, struct histogram *histo)
-{
- if ( fwrite(histo, sizeof(*histo), 1, stream) !=1) {
- perror("Write error");
- }
- return nread;
-}
-\end{lstlisting}
-%\normalsize
+\includecodesnip{listati/WriteStruct.c}
in cui si specifica la dimensione dell'intera struttura ed un solo
elemento.
Le \acr{glibc} definiscono altre due funzioni per l'I/O binario,
\funcd{fread\_unlocked} e \funcd{fwrite\_unlocked} 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), i loro prototipi sono:
+applicazioni \itindex{thread} \textit{multi-thread} (si veda
+sez.~\ref{sec:file_stream_thread} per i dettagli), i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
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
+meccanismo visto in sez.~\ref{sec:proc_var_passing}; per questo motivo se
si passa un'espressione si possono avere effetti indesiderati.
-Invece \func{fgetc} è 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 nel tipo di argomento).
+Invece \func{fgetc} è 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 argomento ad un altra funzione (e non si hanno i problemi accennati in
+precedenza nel tipo di argomento).
Le tre funzioni restituiscono tutte un \ctyp{unsigned char} convertito
ad \ctyp{int} (si usa \ctyp{unsigned char} in modo da evitare
\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.
+ \param{stream}. È una sempre una funzione.
\funcdecl{wint\_t getwchar(void)} Equivalente a \code{getwc(stdin)}.
\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
+ \funcdecl{int fputc(int c, FILE *stream)} Scrive il carattere \param{c} su
\param{stream}. È una sempre una funzione.
- \funcdecl{int putchar(void)} Equivalente a \code{putc(stdin)}.
+ \funcdecl{int putchar(int c)} Equivalente a \code{putc(stdout)}.
\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 è \val{EOF}.}
\end{functions}
-Tutte queste funzioni scrivono sempre un byte alla volta, anche se
-prendono come parametro un \ctyp{int} (che pertanto deve essere ottenuto
-con un cast da un \ctyp{unsigned char}). Anche il valore di ritorno è
-sempre un intero; in caso di errore o fine del file il valore di ritorno
-è \val{EOF}.
+Tutte queste funzioni scrivono sempre un byte alla volta, anche se prendono
+come argomento un \ctyp{int} (che pertanto deve essere ottenuto con un cast da
+un \ctyp{unsigned char}). Anche il valore di ritorno è sempre un intero; in
+caso di errore o fine del file il valore di ritorno è \val{EOF}.
Come nel caso dell'I/O binario con \func{fread} e \func{fwrite} le \acr{glibc}
provvedono come estensione, per ciascuna delle funzioni precedenti,
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
+sez.~\ref{sec:file_fseek}) i caratteri rimandati indietro vengono
scartati.
viene restituito un \val{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}\index{buffer overflow}, con sovrascrittura della memoria del
-processo adiacente al buffer.\footnote{questa tecnica è spiegata in dettaglio
- e con molta efficacia nell'ormai famoso articolo di Aleph1 \cite{StS}.}
-
-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
-che lancia una shell).
+stringa letta superi le dimensioni del buffer, si avrà un
+\itindex{buffer~overflow} \textit{buffer overflow}, con sovrascrittura della
+memoria del processo adiacente al buffer.\footnote{questa tecnica è spiegata
+ in dettaglio e con molta efficacia nell'ormai famoso articolo di Aleph1
+ \cite{StS}.}
+
+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 \itindex{stack} \textit{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 che 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
\acr{glibc} supportano una serie di altre funzioni, estensioni di tutte quelle
illustrate finora (eccetto \func{gets} e \func{puts}), che eseguono
esattamente le stesse operazioni delle loro equivalenti, evitando però il lock
-implicito dello stream (vedi \secref{sec:file_stream_thread}). Come per le
+implicito dello stream (vedi sez.~\ref{sec:file_stream_thread}). Come per le
altre forma di I/O, dette funzioni hanno lo stesso nome della loro analoga
normale, con l'aggiunta dell'estensione \code{\_unlocked}.
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 copiare la
+argomento l'indirizzo del puntatore al buffer su cui si vuole copiare 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
+locale); come secondo argomento 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 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 restituiti indietro (si noti infatti
+come per entrambi gli argomenti si siano usati dei
+\itindex{value~result~argument} \textit{value result argument}, passando dei
+puntatori anziché i valori delle variabili, secondo la tecnica spiegata in
+sez.~\ref{sec:proc_var_passing}).
-Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL}
-e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria
+Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{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 letta. 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\index{memory leak} occorre ricordarsi di liberare
-\var{ptr} con una \func{free}.
+essere il seguente:
+\includecodesnip{listati/getline.c}
+e per evitare \itindex{memory~leak} \textit{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
\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
+\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}, con conseguente sovrascrittura di altre variabili e
-possibili \textit{buffer overflow}\index{buffer overflow}; per questo motivo
-si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è:
+possibili \itindex{buffer~overflow} \textit{buffer overflow}; per questo
+motivo si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo
+è:
\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
La parte più complessa delle funzioni di scrittura formattata è il formato
della stringa \param{format} che indica le conversioni da fare, e da cui
-deriva anche il numero dei parametri che dovranno essere passati a seguire (si
-noti come tutte queste funzioni siano \textit{variadic}\index{variadic},
+deriva anche il numero degli argomenti che dovranno essere passati a seguire
+(si noti come tutte queste funzioni siano \index{variadic} \textit{variadic},
prendendo un numero di argomenti variabile che dipende appunto da quello che
si è specificato in \param{format}).
\hline
\hline
\cmd{\%d} &\ctyp{int} & Stampa un numero intero in formato decimale
- con segno \\
- \cmd{\%i} &\ctyp{int} & Identico a \cmd{\%i} in output, \\
- \cmd{\%o} &\ctyp{unsigned int}& Stampa un numero intero come ottale\\
+ con segno.\\
+ \cmd{\%i} &\ctyp{int} & Identico a \cmd{\%i} in output.\\
+ \cmd{\%o} &\ctyp{unsigned int}& Stampa un numero intero come ottale.\\
\cmd{\%u} &\ctyp{unsigned int}& Stampa un numero intero in formato
- decimale senza segno \\
+ decimale senza segno.\\
\cmd{\%x},
\cmd{\%X} &\ctyp{unsigned int}& Stampano un intero in formato esadecimale,
rispettivamente con lettere minuscole e
- maiuscole. \\
+ maiuscole.\\
\cmd{\%f} &\ctyp{double} & Stampa un numero in virgola mobile con la
- notazione a virgola fissa \\
+ notazione a virgola fissa.\\
\cmd{\%e},
\cmd{\%E} &\ctyp{double} & Stampano un numero in virgola mobile con la
notazione esponenziale, rispettivamente con
- lettere minuscole e maiuscole. \\
+ lettere minuscole e maiuscole.\\
\cmd{\%g},
\cmd{\%G} &\ctyp{double} & Stampano un numero in virgola mobile con la
notazione più appropriate delle due precedenti,
rispettivamente con lettere minuscole e
- maiuscole. \\
+ maiuscole.\\
\cmd{\%a},
\cmd{\%A} &\ctyp{double} & Stampano un numero in virgola mobile in
- notazione esadecimale frazionaria\\
- \cmd{\%c} &\ctyp{int} & Stampa un carattere singolo\\
- \cmd{\%s} &\ctyp{char *} & Stampa una stringa \\
- \cmd{\%p} &\ctyp{void *} & Stampa il valore di un puntatore\\
- \cmd{\%n} &\ctyp{\&int} & Prende il numero di caratteri stampati finora\\
- \cmd{\%\%}& & Stampa un \% \\
+ notazione esadecimale frazionaria.\\
+ \cmd{\%c} &\ctyp{int} & Stampa un carattere singolo.\\
+ \cmd{\%s} &\ctyp{char *} & Stampa una stringa.\\
+ \cmd{\%p} &\ctyp{void *} & Stampa il valore di un puntatore.\\
+ \cmd{\%n} &\ctyp{\&int} & Prende il numero di caratteri stampati finora.\\
+ \cmd{\%\%}& & Stampa un \%.\\
\hline
\end{tabular}
\caption{Valori possibili per gli specificatori di conversione in una
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
-\tabref{tab:file_format_spec}) che la conclude.
+tab.~\ref{tab:file_format_spec}) che la conclude.
\begin{table}[htb]
\centering
\val{0} & La conversione è riempita con zeri alla sinistra del valore.\\
\val{-} & La conversione viene allineata a sinistra sul bordo del campo.\\
\val{' '}& Mette uno spazio prima di un numero con segno di valore
- positivo\\
+ positivo.\\
\val{+} & Mette sempre il segno ($+$ o $-$) prima di un numero.\\
\hline
\end{tabular}
\begin{itemize*}
\item uno specificatore del parametro da usare (terminato da un \val{\$}),
\item uno o più flag (i cui valori possibili sono riassunti in
- \tabref{tab:file_format_flag}) che controllano il formato di stampa della
+ tab.~\ref{tab:file_format_flag}) che controllano il formato di stampa della
conversione,
\item uno specificatore di larghezza (un numero decimale), eventualmente
seguito (per i numeri in virgola mobile) da un specificatore di precisione
(un altro numero decimale),
\item uno specificatore del tipo di dato, che ne indica la dimensione (i cui
- valori possibili sono riassunti in \tabref{tab:file_format_type}).
+ valori possibili sono riassunti in tab.~\ref{tab:file_format_type}).
\end{itemize*}
\textbf{Valore} & \textbf{Significato} \\
\hline
\hline
- \cmd{hh} & una conversione intera corrisponde a un \ctyp{char} con o senza
+ \cmd{hh} & Una conversione intera corrisponde a un \ctyp{char} con o senza
segno, o il puntatore per il numero dei parametri \cmd{n} è di
tipo \ctyp{char}.\\
- \cmd{h} & una conversione intera corrisponde a uno \ctyp{short} con o
+ \cmd{h} & Una conversione intera corrisponde a uno \ctyp{short} con o
senza segno, o il puntatore per il numero dei parametri \cmd{n}
è di tipo \ctyp{short}.\\
- \cmd{l} & una conversione intera corrisponde a un \ctyp{long} con o
+ \cmd{l} & Una conversione intera corrisponde a un \ctyp{long} con o
senza segno, o il puntatore per il numero dei parametri \cmd{n}
è di tipo \ctyp{long}, o il carattere o la stringa seguenti
sono in formato esteso.\\
- \cmd{ll} & una conversione intera corrisponde a un \ctyp{long long} con o
+ \cmd{ll} & Una conversione intera corrisponde a un \ctyp{long long} con o
senza segno, o il puntatore per il numero dei parametri \cmd{n}
è di tipo \ctyp{long long}.\\
- \cmd{L} & una conversione in virgola mobile corrisponde a un
+ \cmd{L} & Una conversione in virgola mobile corrisponde a un
\ctyp{double}.\\
- \cmd{q} & sinonimo di \cmd{ll}.\\
- \cmd{j} & una conversione intera corrisponde a un \type{intmax\_t} o
+ \cmd{q} & Sinonimo di \cmd{ll}.\\
+ \cmd{j} & Una conversione intera corrisponde a un \type{intmax\_t} o
\type{uintmax\_t}.\\
- \cmd{z} & una conversione intera corrisponde a un \type{size\_t} o
+ \cmd{z} & Una conversione intera corrisponde a un \type{size\_t} o
\type{ssize\_t}.\\
- \cmd{t} & una conversione intera corrisponde a un \type{ptrdiff\_t}.\\
+ \cmd{t} & Una conversione intera corrisponde a un \type{ptrdiff\_t}.\\
\hline
\end{tabular}
\caption{Il modificatore di tipo di dato per il formato di \func{printf}}
Una versione alternativa delle funzioni di output formattato, che permettono
di usare il puntatore ad una lista di argomenti (vedi
-\secref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
+sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
\funcd{vsprintf}, i cui prototipi sono:
\begin{functions}
\headdecl{stdio.h}
\bodydesc{Le funzioni ritornano il numero di caratteri stampati.}
\end{functions}
\noindent con queste funzioni diventa possibile selezionare gli argomenti che
-si vogliono passare ad una routine di stampa, passando direttamente la lista
-tramite il parametro \param{ap}. Per poter far questo ovviamente la lista dei
-parametri dovrà essere opportunamente trattata (l'argomento è esaminato in
-\secref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
+si vogliono passare ad una funzione di stampa, passando direttamente la lista
+tramite l'argomento \param{ap}. Per poter far questo ovviamente la lista degli
+argomenti dovrà essere opportunamente trattata (l'argomento è esaminato in
+sez.~\ref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
\param{ap} non sarà più utilizzabile (in generale dovrebbe essere eseguito un
\code{va\_end(ap)} ma in Linux questo non è necessario).
Identica a \func{vsprintf}, ma non scrive su \param{str} più di
\param{size} caratteri.
\end{prototype}
-\noindent in modo da evitare possibili buffer overflow\index{buffer overflow}.
+\noindent in modo da evitare possibili \itindex{buffer~overflow} buffer
+overflow.
Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
\bodydesc{Le funzioni ritornano il numero di caratteri stampati.}
\end{functions}
-Entrambe le funzioni prendono come parametro \param{strptr} che deve essere
+
+Entrambe le funzioni prendono come argomento \param{strptr} che deve essere
l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà
-restituito (si ricordi quanto detto in \secref{sec:proc_var_passing} a
-proposito dei \textit{value result argument}) l'indirizzo della stringa
-allocata automaticamente dalle funzioni. Occorre inoltre ricordarsi di
-invocare \func{free} per liberare detto puntatore quando la stringa non serve
-più, onde evitare memory leak\index{memory leak}.
+restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a
+proposito dei \itindex{value~result~argument} \textit{value result argument})
+l'indirizzo della stringa allocata automaticamente dalle funzioni. Occorre
+inoltre ricordarsi di invocare \func{free} per liberare detto puntatore quando
+la stringa non serve più, onde evitare \itindex{memory~leak} \textit{memory
+ leak}.
Infine una ulteriore estensione GNU definisce le due funzioni \func{dprintf} e
\func{vdprintf}, che prendono un file descriptor al posto dello stream. Altre
\headdecl{stdio.h} \funcdecl{int scanf(const char *format, ...)} Esegue una
scansione di \file{stdin} cercando una corrispondenza di quanto letto con il
formato dei dati specificato da \param{format}, ed effettua le relative
- conversione memorizzando il risultato nei parametri seguenti.
+ conversione memorizzando il risultato negli argomenti seguenti.
\funcdecl{int fscanf(FILE *stream, const char *format, ...)} Analoga alla
precedente, ma effettua la scansione su \param{stream}.
Le funzioni leggono i caratteri dallo stream (o dalla stringa) di input ed
eseguono un confronto con quanto indicato in \param{format}, la sintassi di
-questo parametro è simile a quella usata per l'analogo di \func{printf}, ma ci
+questo argomento è simile a quella usata per l'analogo di \func{printf}, ma ci
sono varie differenze. Le funzioni di input infatti sono più orientate verso
la lettura di testo libero che verso un input formattato in campi fissi. Uno
spazio in \param{format} corrisponde con un numero qualunque di caratteri di
-separazione (che possono essere spazi, tabulatori, virgole etc.), mentre
+separazione (che possono essere spazi, tabulatori, virgole ecc.), mentre
caratteri diversi richiedono una corrispondenza esatta. Le direttive di
conversione sono analoghe a quelle di \func{printf} e si trovano descritte in
dettaglio nelle pagine di manuale e nel manuale delle \acr{glibc}.
punto prestabilito; sempre che l'operazione di riposizionamento sia supportata
dal file sottostante lo stream, quando cioè si ha a che fare con quello che
viene detto un file ad \textsl{accesso casuale}.\footnote{dato che in un
- sistema Unix esistono vari tipi di file, come le fifo ed i file di
- dispositivo\index{file!di dispositivo}, non è scontato che questo sia sempre
- vero.}
+ sistema Unix esistono vari tipi di file, come le fifo ed i
+ \index{file!di~dispositivo} file di dispositivo, non è scontato che questo
+ sia sempre vero.}
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
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
+sostanzialmente le stesse operazioni, ma usano argomenti di tipo diverso. Le
funzioni tradizionali usate per il riposizionamento della posizione in uno
stream sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono:
\begin{functions}
\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
+descriptor, e gli argomenti, 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
+sez.~\ref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1
in caso di errore. La funzione \func{rewind} riporta semplicemente la
posizione corrente all'inizio dello stream, ma non esattamente equivalente ad
una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i
In Linux, a partire dalle glibc 2.1, sono presenti anche le due funzioni
\func{fseeko} e \func{ftello}, che sono assolutamente identiche alle
precedenti \func{fseek} e \func{ftell} ma hanno argomenti di tipo
-\type{off\_t} anziché di tipo \ctyp{long int}.
+\type{off\_t} anziché di tipo \ctyp{long int}. Dato che \ctyp{long} è nella
+gran parte dei casi un intero a 32 bit, questo diventa un problema quando la
+posizione sul file viene espressa con un valore a 64 bit come accade nei
+sistemi più moderni.
In questa sezione esamineremo alcune funzioni avanzate che permettono di
eseguire operazioni particolari sugli stream, come leggerne gli attributi,
controllarne le modalità di bufferizzazione, gestire direttamente i lock
-impliciti per la programmazione multi thread.
+impliciti per la programmazione \itindex{thread} \textit{multi-thread}.
\subsection{Le funzioni di controllo}
\subsection{Il controllo della bufferizzazione}
\label{sec:file_buffering_ctrl}
-Come accennato in \secref{sec:file_buffering} le librerie definiscono una
+Come accennato in sez.~\ref{sec:file_buffering} le librerie definiscono una
serie di funzioni che permettono di controllare il comportamento degli stream;
se non si è specificato nulla, la modalità di buffering viene decisa
autonomamente sulla base del tipo di file sottostante, ed i buffer vengono
(come delle scritture accidentali sul buffer) e non assicura la scelta delle
dimensioni ottimali, è sempre meglio lasciare allocare il buffer alle funzioni
di libreria, che sono in grado di farlo in maniera ottimale e trasparente
-all'utente (in quanto la disallocazione avviene automaticamente). Inoltre
+all'utente (in quanto la deallocazione avviene automaticamente). Inoltre
siccome alcune implementazioni usano parte del buffer per mantenere delle
informazioni di controllo, non è detto che le dimensioni dello stesso
coincidano con quelle su cui viene effettuato l'I/O.
\const{\_IOFBF} & \textit{fully buffered}\\
\hline
\end{tabular}
- \caption{Valori del parametro \param{mode} di \func{setvbuf}
- per l'impostazione delle modalità di bufferizzazione.}
+ \caption{Valori dell'argomento \param{mode} di \func{setvbuf}
+ per l'impostazione delle modalità di bufferizzazione.}
\label{tab:file_stream_buf_mode}
\end{table}
Per evitare che \func{setvbuf} imposti il buffer basta passare un valore
-\val{NULL} per \param{buf} e la funzione ignorerà il parametro \param{size}
+\val{NULL} per \param{buf} e la funzione ignorerà l'argomento \param{size}
usando il buffer allocato automaticamente dal sistema. Si potrà comunque
modificare la modalità di bufferizzazione, passando in \param{mode} uno degli
-opportuni valori elencati in \tabref{tab:file_stream_buf_mode}. Qualora si
+opportuni valori elencati in tab.~\ref{tab:file_stream_buf_mode}. Qualora si
specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size}
vengono sempre ignorati.
Si ricordi comunque che lo scarico dei dati dai buffer effettuato da queste
funzioni non comporta la scrittura di questi su disco; se si vuole che il
kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre
-usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}).
+usare \func{sync} o \func{fsync} (si veda~sez.~\ref{sec:file_sync}).
Infine esistono anche circostanze in cui si vuole scartare tutto l'output
pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è:
compresi gli eventuali caratteri rimandati indietro con \func{ungetc}.
-\subsection{Gli stream e i thread}
+\subsection{Gli \textit{stream} e i \textit{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
+\itindbeg{thread}
+
+Gli stream possono essere usati in applicazioni \textit{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 con i thread.
+\textit{thread}, dato che l'implementazione delle librerie è influenzata
+pesantemente dalle richieste necessarie per garantirne l'uso con i
+\textit{thread}.
Lo standard POSIX richiede che le operazioni sui file siano atomiche rispetto
-ai thread, per questo le operazioni sui buffer effettuate dalle funzioni di
-libreria durante la lettura e la scrittura di uno stream devono essere
-opportunamente protette (in quanto il sistema assicura l'atomicità solo per le
-system call). Questo viene fatto associando ad ogni stream un opportuno blocco
-che deve essere implicitamente acquisito prima dell'esecuzione di qualunque
-operazione.
-
-Ci sono comunque situazioni in cui questo non basta, come quando un thread
-necessita di compiere più di una operazione sullo stream atomicamente, per
-questo motivo le librerie provvedono anche delle funzioni \funcd{flockfile},
-\funcd{ftrylockfile} e \funcd{funlockfile}, che permettono la gestione
-esplicita dei blocchi sugli stream; esse sono disponibili definendo
-\macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono:
+ai \textit{thread}, per questo le operazioni sui buffer effettuate dalle
+funzioni di libreria durante la lettura e la scrittura di uno stream devono
+essere opportunamente protette (in quanto il sistema assicura l'atomicità solo
+per le system call). Questo viene fatto associando ad ogni stream un opportuno
+blocco che deve essere implicitamente acquisito prima dell'esecuzione di
+qualunque operazione.
+
+Ci sono comunque situazioni in cui questo non basta, come quando un
+\textit{thread} necessita di compiere più di una operazione sullo stream
+atomicamente, per questo motivo le librerie provvedono anche delle funzioni
+\funcd{flockfile}, \funcd{ftrylockfile} e \funcd{funlockfile}, che permettono
+la gestione esplicita dei blocchi sugli stream; esse sono disponibili
+definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
Ma, vista la complessità delle strutture di dati coinvolte, le operazioni di
blocco non sono del tutto indolori, e quando il locking dello stream non è
-necessario (come in tutti i programmi che non usano i thread), tutta la
-procedura può comportare dei costi pesanti in termini di prestazioni. Per
+necessario (come in tutti i programmi che non usano i \textit{thread}), tutta
+la procedura può comportare dei costi pesanti in termini di prestazioni. Per
questo motivo abbiamo visto come alle usuali funzioni di I/O non formattato
siano associate delle versioni \code{\_unlocked} (alcune previste dallo stesso
standard POSIX, altre aggiunte come estensioni dalle \acr{glibc}) che possono
accade per \func{getc} e \func{putc}) sono realizzate come macro.
La sostituzione di tutte le funzioni di I/O con le relative versioni
-\code{\_unlocked} in un programma che non usa i thread è però un lavoro
-abbastanza noioso; per questo motivo le \acr{glibc} forniscono al
+\code{\_unlocked} in un programma che non usa i \textit{thread} è però un
+lavoro abbastanza noioso; per questo motivo le \acr{glibc} forniscono al
programmatore pigro un'altra via\footnote{anche questa mutuata da estensioni
introdotte in Solaris.} da poter utilizzare per disabilitare in blocco il
locking degli stream: l'uso della funzione \funcd{\_\_fsetlocking}, il cui
di blocco dello stream.
\end{basedescript}
+\itindend{thread}
+
+
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
+
+% LocalWords: stream cap system call kernel Ritchie glibc descriptor Stevens
+% LocalWords: buf read write filesystem st blksize stat sez l'header stdio BSD
+% LocalWords: nell'header stdin shell stdout stderr error freopen flush line
+% LocalWords: unbuffered buffered newline fully SVr fopen fdopen POSIX const
+% LocalWords: char path int fildes NULL errno malloc fcntl fclose fflush tab
+% LocalWords: dup fifo socket append EXCL ccs STRING IRUSR IWUSR IRGRP IWGRP
+% LocalWords: IROTH IWOTH umask fseek fsetpos rewind SEEK CUR EOF EBADF close
+% LocalWords: sync fcloseall SOURCE void stdlib of feof ferror clearerr l'I ws
+% LocalWords: unlocked fread fwrite size ptr nmemb nelem gcc padding point str
+% LocalWords: lock thread fgetc getc getchar dell'overhead altresì unsigned ap
+% LocalWords: getwc fgetwc getwchar wint wchar WEOF putc fputc putchar dell'I
+% LocalWords: SVID getw putw parsing peeking ahead ungetc gets fgets string Di
+% LocalWords: overflow Aleph stack fputs puts fgetws fputws getline ssize leak
+% LocalWords: realloc value result argument memory getdelim delim printf short
+% LocalWords: fprintf sprintf format snprintf variadic long double intmax list
+% LocalWords: uintmax ptrdiff vprintf vfprintf vsprintf vsnprintf asprintf lex
+% LocalWords: vasprintf strptr dprintf vdprintf print scanf fscanf sscanf flex
+% LocalWords: vscanf vfscanf vsscanf bison parser yacc like off VMS whence pos
+% LocalWords: lseek ftell fgetpos fpos fseeko ftello fileno Solaris freadable
+% LocalWords: fwritable ext freading fwriting buffering setvbuf BUFSIZ setbuf
+% LocalWords: IONBF IOLBF IOFBF setbuffer setlinebuf flbf fbufsize flushlbf hh
+% LocalWords: fsync fpurge flockfile ftrylockfile funlockfile SAFE FUNCTIONS
+% LocalWords: locking fsetlocking type BYCALLER QUERY ll