X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=filestd.tex;h=ce45b85454f341672099825d34e7f686544a160f;hp=0232bc89be106489c6393b1ec4c65192804792d3;hb=193d612d40c5f81f5559ea6e11e70f6b6e51fb39;hpb=c4e84d074b7b59b920ab493e32d61d5f3ae2ff15 diff --git a/filestd.tex b/filestd.tex index 0232bc8..ce45b85 100644 --- a/filestd.tex +++ b/filestd.tex @@ -15,7 +15,7 @@ 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'input/output, mentre tratteremo le caratteristiche più avanzate dell'interfaccia nell'ultima sezione. @@ -26,7 +26,7 @@ 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. -Questa interfaccia però non provvede le funzionalità previste dallo standard +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 @@ -39,7 +39,7 @@ costituire il nucleo\footnote{queste funzioni sono state implementate la prima \index{file!stream|(} -Come più volte ribadito, l'interfaccia dei file descriptor è un'interfaccia di +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. @@ -49,20 +49,20 @@ dimensioni del blocco di dati (l'argomento \param{buf} di \func{read} e 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 \struct{stat}), che di norma corrispondono alle -dimensioni dei settori fisici in cui è suddiviso il disco. +dimensioni dei settori fisici in cui è suddiviso il disco. 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 +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 +\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 +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 @@ -79,7 +79,7 @@ sez.~\ref{sec:file_access_control} per il controllo di accesso. \label{sec:file_FILE} -Per ragioni storiche la struttura di dati che rappresenta uno stream è stata +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 @@ -88,7 +88,7 @@ stato e di fine del file. Per questo motivo gli utenti non devono mai utilizzare direttamente o allocare 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 +(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 argomenti solo variabili di questo tipo, che diventa accessibile includendo l'header file \file{stdio.h}. @@ -104,36 +104,36 @@ questi tre stream sono identificabili attraverso dei nomi simbolici definiti nell'header \file{stdio.h} che sono: \begin{basedescript}{\desclabelwidth{3.0cm}} -\item[\var{FILE *stdin}] Lo \textit{standard input} cioè lo stream da +\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 + è associato dalla shell all'input del terminale e prende i caratteri dalla tastiera. -\item[\var{FILE *stdout}] Lo \textit{standard output} cioè lo stream su - cui il processo invia ordinariamente i dati in uscita. Normalmente è +\item[\var{FILE *stdout}] Lo \textit{standard output} 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 error} 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 +\item[\var{FILE *stderr}] Lo \textit{standard error} 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{basedescript} 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 +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 +hanno problemi di portabilità e si vuole essere sicuri, diventa opportuno usare la funzione \func{freopen}. -\subsection{Le modalità di bufferizzazione} +\subsection{Le modalità di bufferizzazione} \label{sec:file_buffering} -La bufferizzazione è una delle caratteristiche principali dell'interfaccia -degli stream; lo scopo è quello di ridurre al minimo il numero di system call +La bufferizzazione è una delle caratteristiche principali dell'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 -uno degli aspetti più comunemente fraintesi, in particolare per quello che +funzionalità è assicurata automaticamente dalla libreria, ma costituisce anche +uno 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 di uno stream normalmente vengono @@ -141,26 +141,26 @@ accumulati in un buffer e poi trasmessi in blocco\footnote{questa operazione viene usualmente chiamata \textsl{scaricamento} dei dati, dal termine inglese \textit{flush}.} tutte le volte che il buffer viene riempito, in maniera asincrona rispetto alla scrittura. Un comportamento analogo avviene -anche in lettura (cioè dal file viene letto un blocco di dati, anche se ne -sono richiesti una quantità inferiore), ma la cosa ovviamente ha rilevanza +anche in lettura (cioè dal file viene letto un blocco di dati, anche 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. Per lo stesso motivo, in tutte le situazioni in cui si sta facendo -dell'input/output interattivo, bisognerà tenere presente le caratteristiche -delle operazioni di scaricamento dei dati, poiché non è detto che ad una +dell'input/output interattivo, bisognerà tenere presente le caratteristiche +delle operazioni di scaricamento dei dati, poiché non è detto che ad una scrittura sullo stream corrisponda una immediata scrittura sul dispositivo (la -cosa è particolarmente evidente quando con le operazioni di input/output su +cosa è particolarmente evidente quando con le operazioni di input/output su terminale). Per rispondere ad esigenze diverse, lo standard definisce tre distinte -modalità in cui può essere eseguita la bufferizzazione, delle quali +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 +\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 @@ -172,39 +172,39 @@ dispositivi interattivi: \end{itemize} Lo standard ANSI C specifica inoltre che lo standard output e lo -standard input siano aperti in modalità \textit{fully buffered} quando +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}. +error non sia mai aperto in modalità \textit{fully buffered}. Linux, come BSD e SVr4, specifica il comportamento predefinito 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ù +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} +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 +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à +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 \textsl{a capo} (\textit{newline}); 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 +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 da uno stream che +con I/O interattivo, è che quando si effettua una lettura da uno stream che comporta l'accesso al kernel\footnote{questo vuol dire che lo stream da cui si - legge è in modalità \textit{unbuffered}.} viene anche eseguito lo scarico di + legge è in modalità \textit{unbuffered}.} viene anche eseguito lo scarico di tutti i buffer degli stream in scrittura. In sez.~\ref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle -opportune funzioni per controllare le modalità di bufferizzazione e lo scarico +opportune funzioni per controllare le modalità di bufferizzazione e lo scarico dei dati. @@ -223,7 +223,7 @@ corrente in uno stream. Le funzioni che si possono usare per aprire uno stream sono solo tre: \funcd{fopen}, \funcd{fdopen} e \funcd{freopen},\footnote{\func{fopen} e - \func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte + \func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte dello standard POSIX.1.} i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -233,11 +233,11 @@ Le funzioni che si possono usare per aprire uno stream sono solo tre: 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. + specificato da \param{stream}, se questo è già aperto prima lo chiude. \bodydesc{Le funzioni ritornano un puntatore valido in caso di successo e - \val{NULL} in caso di errore, in tal caso \var{errno} assumerà il valore - ricevuto dalla funzione sottostante di cui è fallita l'esecuzione. + \val{NULL} in caso di errore, in tal caso \var{errno} assumerà il 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 @@ -245,15 +245,15 @@ Le funzioni che si possono usare per aprire uno stream sono solo tre: \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 +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 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 +L'uso più comune di \func{freopen} è per redirigere uno dei tre file 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 +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 @@ -271,16 +271,16 @@ aperti con le funzioni delle librerie standard del C. \hline \hline \texttt{r} & Il file viene aperto, l'accesso viene posto in sola - lettura, 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.\\ + 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.\\ + 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.\\ + lettura, lo stream è posizionato all'inizio del file.\\ % \hline \texttt{a} & Il file viene aperto (o creato se non esiste) in \itindex{append~mode} \textit{append mode}, l'accesso viene @@ -289,44 +289,44 @@ aperti con le funzioni delle librerie standard del C. \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 + \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 +In realtà lo standard ANSI C prevede un totale di 15 possibili valori 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 +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 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. +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 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à +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} 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 +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. Nel caso si usi \func{fdopen} i valori specificati da \param{mode} devono -essere compatibili con quelli con cui il file descriptor è stato aperto. +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 sez.~\ref{sec:file_io}) sono cancellate. Il -file non viene duplicato e verrà chiuso alla chiusura dello stream. +file non viene duplicato e verrà chiuso alla chiusura dello stream. I nuovi file saranno creati secondo quanto visto in sez.~\ref{sec:file_ownership_management} ed avranno i permessi di accesso @@ -335,54 +335,54 @@ impostati al valore \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'è +In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è di mezzo una bufferizzazione; per questo motivo lo standard ANSI C richiede che ci sia un'operazione di posizionamento fra un'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 +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 +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 -un'operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è +un'operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è sufficiente a garantire la sincronizzazione. -Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione -(si veda sez.~\ref{sec:file_buffering_ctrl}) fintanto che non si è effettuato +Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione +(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 è: +Uno stream viene chiuso con la funzione \funcd{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 \val{EOF} in caso di errore, nel qual caso imposta \var{errno} a \errval{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 + 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 +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 +essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare 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 -\macro{\_GNU\_SOURCE}, il suo prototipo è: +\macro{\_GNU\_SOURCE}, il suo prototipo è: \begin{prototype}{stdio.h}{int fcloseall(void)} Chiude tutti gli stream. \bodydesc{Restituisce 0 se non ci sono errori ed \val{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 +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 sez.~\ref{sec:proc_exit}). @@ -391,10 +391,10 @@ visto in sez.~\ref{sec:proc_exit}). \subsection{Lettura e scrittura su uno stream} \label{sec:file_io} -Una delle caratteristiche più utili dell'interfaccia degli stream è la +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: +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 sez.~\ref{sec:file_binary_io}. @@ -404,10 +404,10 @@ modalit \item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}. \end{enumerate*} -ed inoltre la modalità di input/output formattato. +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 +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 \ctyp{int}) \val{EOF}\footnote{la costante deve essere @@ -419,7 +419,7 @@ che si appoggiano a delle system call, esse non impostano direttamente la variabile \var{errno}, che mantiene il valore impostato dalla system call che ha riportato l'errore. -Siccome la condizione di end-of-file è anch'essa segnalata come errore, nasce +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 impostato in @@ -428,7 +428,7 @@ 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 è +\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 @@ -444,17 +444,17 @@ questi due flag possono essere riletti dalle funzioni \funcd{feof} e i relativi flag sono impostati.} \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 +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 \funcd{clearerr}, il cui prototipo è: +la funzione \funcd{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 funzione una volta che si sia identificata e -corretta la causa di un errore per evitare di mantenere i flag attivi, così da +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 sez.~\ref{sec:file_stream_thread}). @@ -463,10 +463,10 @@ dello stream (vedi sez.~\ref{sec:file_stream_thread}). \subsection{Input/output binario} \label{sec:file_binary_io} -La prima modalità di input/output non formattato ricalca quella della +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 +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 \funcd{fread} ed \funcd{fwrite}; i loro prototipi sono: \begin{functions} @@ -488,36 +488,36 @@ i loro prototipi sono: 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 +tipico è quello in cui si salva un vettore (o un certo numero dei suoi elementi) con una chiamata del tipo: \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: +caso è invece quello in cui si vuole trasferire su file una struttura; +si avrà allora una chiamata tipo: \includecodesnip{listati/WriteStruct.c} 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 +In realtà quello che conta nel trasferimento dei dati sono le dimensioni totali, che sono sempre pari al prodotto \code{size * nelem}; la sola -differenza è che le funzioni non ritornano il numero di byte scritti, +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 impostata alla fine del file (e non a quella corrispondente -alla quantità di dati letti). +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 +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 +occorrerà usare \func{feof} e \func{ferror} per stabilire la natura del problema. -Benché queste funzioni assicurino la massima efficienza per il +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 @@ -525,15 +525,15 @@ 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 +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 +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 prendere -le opportune precauzioni (in genere usare un formato di più alto livello che +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. @@ -562,7 +562,7 @@ sez.~\ref{sec:file_stream_thread} per i dettagli), i loro prototipi sono: \subsection{Input/output a caratteri} \label{sec:file_char_io} -La seconda modalità di input/output è quella a caratteri, in cui si +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, \funcd{fgetc}, \funcd{getc} e \funcd{getchar}, i rispettivi prototipi sono: @@ -570,57 +570,57 @@ rispettivi prototipi sono: \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. + 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. È sempre una funzione. + restituisce come intero. È sempre una funzione. \funcdecl{int getchar(void)} Equivalente a \code{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 è \val{EOF}.} + di ritorno è \val{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{getc} è ottimizzata al massimo e normalmente +differenza è che \func{getc} è 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 +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 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 +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 -l'espansione del segno). In questo modo il valore di ritorno è sempre +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, \funcd{getwc}, \funcd{fgetwc} e \funcd{getwchar}, che invece di un carattere di un byte restituiscono un -carattere in formato esteso (cioè di tipo \ctyp{wint\_t}), il loro prototipo -è: +carattere in formato esteso (cioè di tipo \ctyp{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. + \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)}. \bodydesc{Tutte queste funzioni leggono un carattere alla volta, in - caso di errore o fine del file il valore di ritorno è \const{WEOF}.} + caso di errore o fine del file il valore di ritorno è \const{WEOF}.} \end{functions} Per scrivere un carattere si possono usare tre funzioni, analoghe alle @@ -630,32 +630,32 @@ loro prototipi sono: \headdecl{stdio.h} \funcdecl{int putc(int c, FILE *stream)} Scrive il carattere \param{c} - su \param{stream}. In genere è implementata come una macro. + su \param{stream}. In genere è implementata come una macro. \funcdecl{int fputc(int c, FILE *stream)} Scrive il carattere \param{c} su - \param{stream}. È una sempre una funzione. + \param{stream}. È una sempre una funzione. \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}.} + fine del file il valore di ritorno è \val{EOF}.} \end{functions} 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}. +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, -un'ulteriore funzione, il cui nome è ottenuto aggiungendo un -\code{\_unlocked}, che esegue esattamente le stesse operazioni, evitando però +un'ulteriore funzione, il cui nome è ottenuto aggiungendo un +\code{\_unlocked}, che esegue esattamente le stesse operazioni, evitando però il lock implicito dello stream. -Per compatibilità con SVID sono inoltre provviste anche due funzioni, +Per compatibilità con SVID sono inoltre provviste anche due funzioni, \funcd{getw} e \funcd{putw}, da usare per leggere e scrivere una \textit{word} -(cioè due byte in una volta); i loro prototipi sono: +(cioè due byte in una volta); i loro prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -668,21 +668,21 @@ Per compatibilit \end{functions} Le funzioni leggono e scrivono una \textit{word} di due byte, usando comunque -una variabile di tipo \ctyp{int}; il loro uso è deprecato in favore dell'uso -di \func{fread} e \func{fwrite}, in quanto non è possibile distinguere il +una variabile di tipo \ctyp{int}; il loro uso è 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 \val{EOF}. -Uno degli usi più frequenti dell'input/output a caratteri è nei programmi di +Uno 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 +effettivamente (la tecnica è detta \textit{peeking ahead}) in modo che il programma possa regolarsi 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 +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 \funcd{ungetc} ed il suo prototipo è: +lettura si chiama \funcd{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 \ctyp{unsigned char}, sullo stream \param{stream}. @@ -690,24 +690,24 @@ lettura si chiama \funcd{ungetc} ed il suo prototipo \bodydesc{La funzione ritorna \param{c} in caso di successo e \val{EOF} in caso di errore.} \end{prototype} -\noindent benché lo standard ANSI C preveda che l'operazione possa +\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 è +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 +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 \val{EOF} la funzione non fa nulla, e -restituisce sempre \val{EOF}; così si può usare \func{ungetc} anche +restituisce sempre \val{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 +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 @@ -720,10 +720,10 @@ 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 si legge o si scrive una riga alla volta; questa è una modalità molto -usata per l'I/O da terminale, ma è anche quella che presenta le -caratteristiche più controverse. +La terza ed ultima modalità di input/output non formattato è quella di linea, +in cui si legge o si scrive una riga alla volta; questa è una modalità molto +usata per l'I/O da terminale, ma è anche quella che presenta le +caratteristiche più controverse. Le funzioni previste dallo standard ANSI C per leggere una linea sono sostanzialmente due, \funcd{gets} e \funcd{fgets}, i cui rispettivi @@ -747,32 +747,32 @@ dallo standard input \func{gets}) di una linea di caratteri (terminata dal carattere \textit{newline}, \verb|'\n'|, quello mappato sul tasto di ritorno a capo della tastiera), 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) +dentro la stringa. Se la lettura incontra la fine del file (o c'è un errore) 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 +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 +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 +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 +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). +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 +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 \code{size-1} caratteri. Se la linea eccede la dimensione del buffer verranno letti solo \code{size-1} -caratteri, ma la stringa sarà sempre terminata correttamente con uno zero -finale; sarà possibile leggere i rimanenti caratteri in una chiamata +caratteri, ma la stringa sarà sempre terminata correttamente con uno zero +finale; sarà possibile leggere i rimanenti caratteri in una chiamata successiva. Per la scrittura di una linea lo standard ANSI C prevede altre due @@ -792,11 +792,11 @@ rispettivi prototipi sono: \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 +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 il ritorno a capo. 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 +\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 analoghe funzioni di input/output a caratteri, anche per l'I/O di @@ -817,26 +817,26 @@ loro prototipi sono: caso di errore o fine del file.} \end{functions} -Il comportamento di queste due funzioni è identico a quello di \func{fgets} e +Il comportamento di queste due funzioni è identico a quello di \func{fgets} e \func{fputs}, a parte il fatto che tutto (numero di caratteri massimo, -terminatore della stringa, newline) è espresso in termini di caratteri estesi -anziché di normali caratteri ASCII. +terminatore della stringa, newline) è espresso in termini di caratteri estesi +anziché di normali caratteri ASCII. Come per l'I/O binario e quello a caratteri, anche per l'I/O di linea le \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 +esattamente le stesse operazioni delle loro equivalenti, evitando però il lock 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}. 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ò +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 +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 @@ -847,7 +847,7 @@ 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, \funcd{getline}, serve per leggere una linea terminata da un -newline, esattamente allo stesso modo di \func{fgets}, il suo prototipo è: +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} copiandola sul buffer indicato da \param{buffer} @@ -863,22 +863,22 @@ La funzione permette di eseguire una lettura senza doversi preoccupare della eventuale lunghezza eccessiva della stringa da leggere. Essa prende come primo 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 +\func{malloc} (non si può passare l'indirizzo di un puntatore ad una 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 +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 +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 +\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ò +puntatore all'inizio del testo della linea letta. Un esempio di codice può essere il seguente: \includecodesnip{listati/getline.c} e per evitare \itindex{memory~leak} \textit{memory leak} occorre ricordarsi di @@ -888,33 +888,33 @@ 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 +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 +La seconda estensione GNU è una generalizzazione di \func{getline} per poter usare come separatore un carattere qualsiasi, la funzione si -chiama \funcd{getdelim} ed il suo prototipo è: +chiama \funcd{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 +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{L'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é +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 \funcd{printf}, \funcd{fprintf} e +\func{printf}; le tre più usate sono \funcd{printf}, \funcd{fprintf} e \funcd{sprintf}, i cui prototipi sono: \begin{functions} \headdecl{stdio.h} @@ -933,24 +933,24 @@ L'output formattato viene eseguito con una delle 13 funzioni della famiglia \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 +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 \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 + Identica a \func{sprintf}, ma non scrive su \param{str} più di \param{size} caratteri. \end{prototype} -La parte più complessa delle funzioni di scrittura formattata è il formato +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 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}). +si è specificato in \param{format}). \begin{table}[htb] \centering @@ -978,7 +978,7 @@ si lettere minuscole e maiuscole.\\ \cmd{\%g}, \cmd{\%G} &\ctyp{double} & Stampano un numero in virgola mobile con la - notazione più appropriate delle due precedenti, + notazione più appropriate delle due precedenti, rispettivamente con lettere minuscole e maiuscole.\\ \cmd{\%a}, @@ -996,7 +996,7 @@ si \label{tab:file_format_spec} \end{table} -La stringa è costituita da caratteri normali (tutti eccetto \texttt{\%}), che +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 @@ -1011,7 +1011,7 @@ tab.~\ref{tab:file_format_spec}) che la conclude. \hline \hline \val{\#} & Chiede la conversione in forma alternativa. \\ - \val{0} & La conversione è riempita con zeri alla sinistra del valore.\\ + \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.\\ @@ -1024,7 +1024,7 @@ tab.~\ref{tab:file_format_spec}) che la conclude. 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: +generale essa è sempre del tipo: \begin{center} \begin{verbatim} % [n. parametro $] [flag] [[larghezza] [. precisione]] [tipo] conversione @@ -1032,11 +1032,11 @@ generale essa \end{center} in cui tutti i valori tranne il \val{\%} e lo specificatore di conversione sono opzionali (e per questo sono indicati fra parentesi quadre); si possono -usare più elementi opzionali, nel qual caso devono essere specificati in +usare più elementi opzionali, nel qual caso devono essere specificati in questo ordine: \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 +\item uno o più flag (i cui valori possibili sono riassunti in tab.~\ref{tab:file_format_flag}) che controllano il formato di stampa della conversione, \item uno specificatore di larghezza (un numero decimale), eventualmente @@ -1059,18 +1059,18 @@ manuale di \func{printf} e nella documentazione delle \acr{glibc}. \hline \hline \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 + 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 senza segno, o il puntatore per il numero dei parametri \cmd{n} - è di tipo \ctyp{short}.\\ + è di tipo \ctyp{short}.\\ \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 + è 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 senza segno, o il puntatore per il numero dei parametri \cmd{n} - è di tipo \ctyp{long long}.\\ + è di tipo \ctyp{long long}.\\ \cmd{L} & Una conversione in virgola mobile corrisponde a un \ctyp{double}.\\ \cmd{q} & Sinonimo di \cmd{ll}.\\ @@ -1109,17 +1109,17 @@ sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e \noindent con queste funzioni diventa possibile selezionare gli argomenti che 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 +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). +\param{ap} non sarà più utilizzabile (in generale dovrebbe essere eseguito un +\code{va\_end(ap)} ma in Linux questo non è necessario). Come per \func{sprintf} anche per \func{vsprintf} esiste una analoga \funcd{vsnprintf} che pone un limite sul numero di caratteri che vengono scritti sulla stringa di destinazione: \begin{prototype}{stdio.h} {vsnprintf(char *str, size\_t size, const char *format, va\_list ap)} - Identica a \func{vsprintf}, ma non scrive su \param{str} più di + Identica a \func{vsprintf}, ma non scrive su \param{str} più di \param{size} caratteri. \end{prototype} \noindent in modo da evitare possibili \itindex{buffer~overflow} buffer @@ -1147,24 +1147,24 @@ sono: \end{functions} Entrambe le funzioni prendono come argomento \param{strptr} che deve essere -l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà +l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà 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 +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 estensioni permettono di scrivere con caratteri estesi. Anche queste funzioni, -il cui nome è generato dalle precedenti funzioni aggiungendo una \texttt{w} +il cui nome è generato dalle precedenti funzioni aggiungendo una \texttt{w} davanti a \texttt{print}, sono trattate in dettaglio nella documentazione delle \acr{glibc}. In corrispondenza alla famiglia di funzioni \func{printf} che si usano per l'output formattato, l'input formattato viene eseguito con le funzioni della -famiglia \func{scanf}; fra queste le tre più importanti sono \funcd{scanf}, +famiglia \func{scanf}; fra queste le tre più importanti sono \funcd{scanf}, \funcd{fscanf} e \funcd{sscanf}, i cui prototipi sono: \begin{functions} \headdecl{stdio.h} \funcdecl{int scanf(const char *format, ...)} Esegue una @@ -1180,7 +1180,7 @@ famiglia \func{scanf}; fra queste le tre pi \bodydesc{Le funzioni ritornano il numero di elementi assegnati. Questi possono essere in numero inferiore a quelli specificati, ed anche zero. - Quest'ultimo valore significa che non si è trovata corrispondenza. In caso + Quest'ultimo valore significa che non si è trovata corrispondenza. In caso di errore o fine del file viene invece restituito \val{EOF}.} \end{functions} \noindent e come per le analoghe funzioni di scrittura esistono le relative @@ -1188,14 +1188,14 @@ famiglia \func{scanf}; fra queste le tre pi lista di argomenti. Tutte le funzioni della famiglia delle \func{scanf} vogliono come argomenti i -puntatori alle variabili che dovranno contenere le conversioni; questo è un -primo elemento di disagio in quanto è molto facile dimenticarsi di questa +puntatori alle variabili che dovranno contenere le conversioni; questo è un +primo elemento di disagio in quanto è molto facile dimenticarsi di questa caratteristica. 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 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 +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 ecc.), mentre @@ -1210,19 +1210,19 @@ sia in grado di effettuare una delle conversioni richieste) la scansione viene interrotta immediatamente e la funzione ritorna lasciando posizionato lo stream al primo carattere che non corrisponde. -Data la notevole complessità di uso di queste funzioni, che richiedono molta +Data la notevole complessità di uso di queste funzioni, che richiedono molta cura nella definizione delle corrette stringhe di formato e sono facilmente -soggette ad errori, e considerato anche il fatto che è estremamente macchinoso +soggette ad errori, e considerato anche il fatto che è estremamente macchinoso recuperare in caso di fallimento nelle corrispondenze, l'input formattato non -è molto usato. In genere infatti quando si ha a che fare con un input +è molto usato. In genere infatti quando si ha a che fare con un input relativamente semplice si preferisce usare l'input di linea ed effettuare scansione e conversione di quanto serve direttamente con una delle funzioni di -conversione delle stringhe; se invece il formato è più complesso diventa più +conversione delle stringhe; se invece il formato è più complesso diventa più facile utilizzare uno strumento come \cmd{flex}\footnote{il programma - \cmd{flex}, è una implementazione libera di \cmd{lex} un generatore di - analizzatori lessicali. Per i dettagli si può fare riferimento al manuale + \cmd{flex}, è una implementazione libera di \cmd{lex} un generatore di + analizzatori lessicali. Per i dettagli si può fare riferimento al manuale \cite{flex}.} per generare un analizzatore lessicale o il -\cmd{bison}\footnote{il programma \cmd{bison} è un clone del generatore di +\cmd{bison}\footnote{il programma \cmd{bison} è un clone del generatore di parser \cmd{yacc}, maggiori dettagli possono essere trovati nel relativo manuale \cite{bison}.} per generare un parser. @@ -1230,22 +1230,22 @@ facile utilizzare uno strumento come \cmd{flex}\footnote{il programma \subsection{Posizionamento su uno stream} \label{sec:file_fseek} -Come per i file descriptor anche per gli stream è possibile spostarsi +Come per i file descriptor anche per gli stream è possibile spostarsi all'interno di un file per effettuare operazioni di lettura o scrittura in un 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 +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 - \index{file!di~dispositivo} file di dispositivo, non è scontato che questo + \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 è +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 è che alcune delle funzioni usate per il riposizionamento sugli +problema è che 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 +ancora stato definito, e che in altri sistemi non è detto che la posizione su un file venga sempre rappresentata con il numero di caratteri dall'inizio (ad -esempio in VMS può essere rappresentata come numero di record, più l'offset +esempio in VMS può essere rappresentata come numero di record, più l'offset rispetto al record corrente). Tutto questo comporta la presenza di diverse funzioni che eseguono @@ -1263,9 +1263,9 @@ stream sono \funcd{fseek} e \funcd{rewind} i cui prototipi sono: all'inizio del file. \end{functions} -L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file +L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file descriptor, e gli argomenti, a parte il tipo, hanno lo stesso significato; in -particolare \param{whence} assume gli stessi valori già visti in +particolare \param{whence} assume gli stessi valori già visti in 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 @@ -1273,13 +1273,13 @@ una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i flag di errore e fine del file. Per ottenere la posizione corrente si usa invece la funzione \funcd{ftell}, il -cui prototipo è: +cui prototipo è: \begin{prototype}{stdio.h}{long ftell(FILE *stream)} Legge la posizione attuale nello stream \param{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ò + 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 \ctyp{long int}} \end{prototype} \noindent la funzione restituisce la posizione come numero di byte @@ -1287,7 +1287,7 @@ dall'inizio dello stream. Queste funzioni esprimono tutte la posizione nel file come un \ctyp{long int}. Dato che (ad esempio quando si usa un filesystem indicizzato a 64 bit) questo -può non essere possibile lo standard POSIX ha introdotto le nuove funzioni +può non essere possibile lo standard POSIX ha introdotto le nuove funzioni \funcd{fgetpos} e \funcd{fsetpos}, che invece usano il nuovo tipo \type{fpos\_t}, ed i cui prototipi sono: \begin{functions} @@ -1306,10 +1306,10 @@ pu 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}. Dato che \ctyp{long} è nella +\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. +sistemi più moderni. @@ -1318,7 +1318,7 @@ sistemi pi 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 +controllarne le modalità di bufferizzazione, gestire direttamente i lock impliciti per la programmazione \itindex{thread} \textit{multi-thread}. @@ -1327,9 +1327,9 @@ impliciti per la programmazione \itindex{thread} \textit{multi-thread}. Al contrario di quanto avviene con i file descriptor, le librerie standard del C non prevedono nessuna funzione come la \func{fcntl} per il controllo degli -attributi dei file. Però, dato che ogni stream si appoggia ad un file -descriptor, si può usare la funzione \funcd{fileno} per ottenere quest'ultimo, -il prototipo della funzione è: +attributi dei file. Però, dato che ogni stream si appoggia ad un file +descriptor, si può usare la funzione \funcd{fileno} per ottenere quest'ultimo, +il prototipo della funzione è: \begin{prototype}{stdio.h}{int fileno(FILE *stream)} Legge il file descriptor sottostante lo stream \param{stream}. @@ -1340,16 +1340,16 @@ il prototipo della funzione \noindent ed in questo modo diventa possibile usare direttamente \func{fcntl}. Questo permette di accedere agli attributi del file descriptor sottostante lo -stream, ma non ci dà nessuna informazione riguardo alle proprietà dello stream -medesimo. Le \acr{glibc} però supportano alcune estensioni derivate da +stream, ma non ci dà nessuna informazione riguardo alle proprietà dello stream +medesimo. Le \acr{glibc} però supportano alcune estensioni derivate da Solaris, che permettono di ottenere informazioni utili. -Ad esempio 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ò +Ad esempio 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 +questo punto necessiterà di informazioni aggiuntive rispetto al semplice +puntatore allo stream; questo può essere evitato con le due funzioni \funcd{\_\_freadable} e \funcd{\_\_fwritable} i cui prototipi sono: \begin{functions} \headdecl{stdio\_ext.h} @@ -1362,25 +1362,25 @@ puntatore allo stream; questo pu \end{functions} \noindent che permettono di ottenere questa informazione. -La conoscenza dell'ultima operazione effettuata su uno stream aperto è utile +La conoscenza dell'ultima operazione effettuata su uno stream aperto è utile in quanto permette di trarre conclusioni sullo stato del buffer e del suo contenuto. Altre due funzioni, \funcd{\_\_freading} e \funcd{\_\_fwriting} -servono a tale scopo, il loro prototipo è: +servono a tale scopo, 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. + 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. + 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 permettono di determinare di che tipo è stata l'ultima +Le due funzioni permettono 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 +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. @@ -1390,18 +1390,18 @@ operazione ci fosse comunque stata. 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 +se non si è specificato nulla, la modalità di buffering viene decisa autonomamente sulla base del tipo di file sottostante, ed i buffer vengono allocati automaticamente. -Però una volta che si sia aperto lo stream (ma prima di aver compiuto -operazioni su di esso) è possibile intervenire sulle modalità di buffering; la -funzione che permette di controllare la bufferizzazione è \funcd{setvbuf}, il -suo prototipo è: +Però una volta che si sia aperto lo stream (ma prima di aver compiuto +operazioni su di esso) è possibile intervenire sulle modalità di buffering; la +funzione che permette di controllare la bufferizzazione è \funcd{setvbuf}, il +suo prototipo è: \begin{prototype}{stdio.h}{int setvbuf(FILE *stream, char *buf, int mode, size\_t size)} - Imposta la bufferizzazione dello stream \param{stream} nella modalità + Imposta la bufferizzazione dello stream \param{stream} nella modalità indicata da \param{mode}, usando \param{buf} come buffer di lunghezza \param{size}. @@ -1410,27 +1410,27 @@ suo prototipo \end{prototype} La funzione permette di controllare tutti gli aspetti della bufferizzazione; -l'utente può specificare un buffer da usare al posto di quello allocato dal +l'utente può specificare un buffer da usare al posto di quello allocato dal sistema passandone alla funzione l'indirizzo in \param{buf} e la dimensione in \param{size}. Ovviamente se si usa un buffer specificato dall'utente questo deve essere stato allocato e rimanere disponibile per tutto il tempo in cui si opera sullo stream. In genere conviene allocarlo con \func{malloc} e disallocarlo dopo la -chiusura del file; ma fintanto che il file è usato all'interno di una -funzione, può anche essere usata una variabile automatica. In \file{stdio.h} è +chiusura del file; ma fintanto che il file è usato all'interno di una +funzione, può anche essere usata una variabile automatica. In \file{stdio.h} è definita la macro \const{BUFSIZ}, che indica le dimensioni generiche del buffer di uno stream; queste vengono usate dalla funzione \func{setbuf}. Non -è detto però che tale dimensione corrisponda sempre al valore ottimale (che -può variare a seconda del dispositivo). +è detto però che tale dimensione corrisponda sempre al valore ottimale (che +può variare a seconda del dispositivo). -Dato che la procedura di allocazione manuale è macchinosa, comporta dei rischi +Dato che la procedura di allocazione manuale è macchinosa, comporta dei rischi (come delle scritture accidentali sul buffer) e non assicura la scelta delle -dimensioni ottimali, è sempre meglio lasciare allocare il buffer alle funzioni +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 deallocazione avviene automaticamente). Inoltre siccome alcune implementazioni usano parte del buffer per mantenere delle -informazioni di controllo, non è detto che le dimensioni dello stesso +informazioni di controllo, non è detto che le dimensioni dello stesso coincidano con quelle su cui viene effettuato l'I/O. \begin{table}[htb] @@ -1438,7 +1438,7 @@ coincidano con quelle su cui viene effettuato l'I/O. \footnotesize \begin{tabular}[c]{|l|l|} \hline - \textbf{Valore} & \textbf{Modalità} \\ + \textbf{Valore} & \textbf{Modalità} \\ \hline \hline \const{\_IONBF} & \textit{unbuffered}\\ @@ -1447,16 +1447,16 @@ coincidano con quelle su cui viene effettuato l'I/O. \hline \end{tabular} \caption{Valori dell'argomento \param{mode} di \func{setvbuf} - per l'impostazione delle modalità di bufferizzazione.} + 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à 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 +\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 tab.~\ref{tab:file_stream_buf_mode}. Qualora si -specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size} +specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size} vengono sempre ignorati. Oltre a \func{setvbuf} le \acr{glibc} definiscono altre tre funzioni per la @@ -1466,42 +1466,42 @@ e \funcd{setlinebuf}; i loro prototipi sono: \headdecl{stdio.h} \funcdecl{void setbuf(FILE *stream, char *buf)} Disabilita la - bufferizzazione se \param{buf} è \val{NULL}, altrimenti usa \param{buf} - come buffer di dimensione \const{BUFSIZ} in modalità \textit{fully buffered}. + bufferizzazione se \param{buf} è \val{NULL}, altrimenti usa \param{buf} + come buffer di dimensione \const{BUFSIZ} in modalità \textit{fully buffered}. \funcdecl{void setbuffer(FILE *stream, char *buf, size\_t size)} Disabilita - la bufferizzazione se \param{buf} è \val{NULL}, altrimenti usa \param{buf} - come buffer di dimensione \param{size} in modalità \textit{fully buffered}. + la bufferizzazione se \param{buf} è \val{NULL}, altrimenti usa \param{buf} + come buffer di dimensione \param{size} in modalità \textit{fully buffered}. - \funcdecl{void setlinebuf(FILE *stream)} Pone lo stream in modalità + \funcdecl{void setlinebuf(FILE *stream)} Pone lo stream in modalità \textit{line buffered}. \end{functions} \noindent tutte queste funzioni sono realizzate con opportune chiamate a -\func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie +\func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie BSD. Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche queste funzioni sono originarie di Solaris.} \funcd{\_\_flbf} e -\funcd{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione +\funcd{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione di uno stream; i cui prototipi sono: \begin{functions} \headdecl{stdio\_ext.h} \funcdecl{int \_\_flbf(FILE *stream)} Restituisce un valore diverso da zero - se \param{stream} è in modalità \textit{line buffered}. + se \param{stream} è in modalità \textit{line buffered}. \funcdecl{size\_t \_\_fbufsize(FILE *stream)} Restituisce le dimensioni del buffer di \param{stream}. \end{functions} -Come già accennato, indipendentemente dalla modalità di bufferizzazione -scelta, si può forzare lo scarico dei dati sul file con la funzione -\funcd{fflush}, il suo prototipo è: +Come già accennato, indipendentemente dalla modalità di bufferizzazione +scelta, si può forzare lo scarico dei dati sul file con la funzione +\funcd{fflush}, il suo prototipo è: \begin{prototype}{stdio.h}{int fflush(FILE *stream)} Forza la scrittura di tutti i dati bufferizzati dello stream \param{stream}. \bodydesc{Restituisce zero in caso di successo, ed \val{EOF} in caso di - errore, impostando \var{errno} a \errval{EBADF} se \param{stream} non è - aperto o non è aperto in scrittura, o ad uno degli errori di + errore, impostando \var{errno} a \errval{EBADF} se \param{stream} non è + aperto o non è aperto in scrittura, o ad uno degli errori di \func{write}.} \end{prototype} \noindent anche di questa funzione esiste una analoga @@ -1509,14 +1509,14 @@ scelta, si pu \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}.} che non effettua il blocco dello stream. -Se \param{stream} è \val{NULL} lo scarico dei dati è forzato per tutti gli -stream aperti. Esistono però circostanze, ad esempio quando si vuole essere +Se \param{stream} è \val{NULL} lo scarico dei dati è forzato per tutti gli +stream aperti. Esistono però circostanze, ad esempio quando si vuole essere sicuri che sia stato eseguito tutto l'output su terminale, in cui serve poter -effettuare lo scarico dei dati solo per gli stream in modalità line buffered; +effettuare lo scarico dei dati solo per gli stream in modalità line buffered; per questo motivo le \acr{glibc} supportano una estensione di Solaris, la -funzione \funcd{\_flushlbf}, il cui prototipo è: +funzione \funcd{\_flushlbf}, il cui prototipo è: \begin{prototype}{stdio-ext.h}{void \_flushlbf(void)} - Forza la scrittura di tutti i dati bufferizzati degli stream in modalità + Forza la scrittura di tutti i dati bufferizzati degli stream in modalità line buffered. \end{prototype} @@ -1526,7 +1526,7 @@ kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre 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 è: +pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è: \begin{prototype}{stdio.h}{int fpurge(FILE *stream)} Cancella i buffer di input e di output dello stream \param{stream}. @@ -1535,8 +1535,8 @@ pendente; per questo si pu errore.} \end{prototype} -La funzione scarta tutti i dati non ancora scritti (se il file è aperto in -scrittura), e tutto l'input non ancora letto (se è aperto in lettura), +La funzione scarta tutti i dati non ancora scritti (se il file è aperto in +scrittura), e tutto l'input non ancora letto (se è aperto in lettura), compresi gli eventuali caratteri rimandati indietro con \func{ungetc}. @@ -1548,20 +1548,20 @@ compresi gli eventuali caratteri rimandati indietro con \func{ungetc}. 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 -\textit{thread}, dato che l'implementazione delle librerie è influenzata +\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 \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 +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 +\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 @@ -1570,10 +1570,10 @@ definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono: \headdecl{stdio.h} \funcdecl{void flockfile(FILE *stream)} Esegue l'acquisizione del lock dello - stream \param{stream}, bloccandosi se il lock non è disponibile. + stream \param{stream}, bloccandosi se il lock non è disponibile. \funcdecl{int ftrylockfile(FILE *stream)} Tenta l'acquisizione del lock - dello stream \param{stream}, senza bloccarsi se il lock non è disponibile. + dello stream \param{stream}, senza bloccarsi se il lock non è disponibile. Ritorna zero in caso di acquisizione del lock, diverso da zero altrimenti. \funcdecl{void funlockfile(FILE *stream)} Rilascia il lock dello @@ -1582,28 +1582,28 @@ definendo \macro{\_POSIX\_THREAD\_SAFE\_FUNCTIONS} ed i loro prototipi sono: \noindent con queste funzioni diventa possibile acquisire un blocco ed eseguire tutte le operazioni volute, per poi rilasciarlo. -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 è +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 \textit{thread}), tutta -la procedura può comportare dei costi pesanti in termini di prestazioni. Per +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 essere usate quando il locking non serve\footnote{in certi casi dette funzioni - possono essere usate, visto che sono molto più efficienti, anche in caso di - necessità di locking, una volta che questo sia stato acquisito manualmente.} -con prestazioni molto più elevate, dato che spesso queste versioni (come + possono essere usate, visto che sono molto più efficienti, anche in caso di + necessità di locking, una volta che questo sia stato acquisito manualmente.} +con prestazioni molto più elevate, dato che spesso queste versioni (come 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 \textit{thread} è però un +\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 -prototipo è: +prototipo è: \begin{prototype}{stdio\_ext.h}{int \_\_fsetlocking (FILE *stream, int type)} - Specifica o richiede a seconda del valore di \param{type} la modalità in cui + Specifica o richiede a seconda del valore di \param{type} la modalità in cui le operazioni di I/O su \param{stream} vengono effettuate rispetto all'acquisizione implicita del blocco sullo stream. @@ -1611,15 +1611,15 @@ prototipo valori \const{FSETLOCKING\_INTERNAL} o \const{FSETLOCKING\_BYCALLER}.} \end{prototype} -La funzione imposta o legge lo stato della modalità di operazione di uno stream +La funzione imposta o legge lo stato della modalità di operazione di uno stream nei confronti del locking a seconda del valore specificato con \param{type}, -che può essere uno dei seguenti: +che può essere uno dei seguenti: \begin{basedescript}{\desclabelwidth{4.0cm}} -\item[\const{FSETLOCKING\_INTERNAL}] Lo stream userà da ora in poi il blocco +\item[\const{FSETLOCKING\_INTERNAL}] Lo stream userà da ora in poi il blocco implicito predefinito. -\item[\const{FSETLOCKING\_BYCALLER}] Al ritorno della funzione sarà l'utente a +\item[\const{FSETLOCKING\_BYCALLER}] Al ritorno della funzione sarà l'utente a dover gestire da solo il locking dello stream. -\item[\const{FSETLOCKING\_QUERY}] Restituisce lo stato corrente della modalità +\item[\const{FSETLOCKING\_QUERY}] Restituisce lo stato corrente della modalità di blocco dello stream. \end{basedescript} @@ -1641,7 +1641,7 @@ che pu % 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: 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