esecuzione.
In genere un programma viene eseguito quando un processo lo fa partire
-eseguendo una funzione della famiglia \texttt{exec}; torneremo su questo e
+eseguendo una funzione della famiglia \func{exec}; torneremo su questo e
sulla la creazione e gestione dei processi nel prossimo capitolo, in questo
affronteremo l'avvio e il funzionamento di un singolo processo partendo dal
punto di vista del programma posto in esecuzione.
discorso dei \textit{thread} comunque in Linux necessita di una trattazione a
parte per la peculiarità dell'implementazione).
-\section{La funzione \texttt{main}}
+\subsection{La funzione \func{main}}
\label{sec:proc_main}
Quando un programma viene lanciato il kernel esegue una opportuna routine di
-avvio, usando il programma \texttt{ld-linux.so}, è questo programma che prima
+avvio, usando il programma \cmd{ld-linux.so}, è questo programma che prima
carica le librerie condivise che servono al programma, effettua il link
dinamico del codice e poi alla fine lo esegue. Infatti, a meno di non aver
specificato il flag \texttt{-static} durante la compilazione, tutti i
programmi in Linux sono incompleti e necessitano di essere linkati alle
librerie condivise quando vengono avviati. La procedura è controllata da
-alcune variabili di ambiente e dal contenuto di \texttt{/etc/ld.so.conf}, i
-dettagli sono riportati nella man page di \texttt{ld.so}.
+alcune variabili di ambiente e dal contenuto di \file{/etc/ld.so.conf}, i
+dettagli sono riportati nella man page di \cmd{ld.so}.
-Il sistema fa partire qualunque programma chiamando la funzione \texttt{main};
+Il sistema fa partire qualunque programma chiamando la funzione \func{main};
sta al programmatore chiamare così la funzione principale del programma da cui
si suppone iniziale l'esecuzione; in ogni caso senza questa funzione lo stesso
linker darebbe luogo ad errori.
-Lo standard ISO C specifica che la funzione \texttt{main} può non avere
+Lo standard ISO C specifica che la funzione \func{main} può non avere
argomenti o prendere due argomenti che rappresentano gli argomenti passati da
linea di comando, in sostanza un prototipo che va sempre bene è il seguente:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
\end{lstlisting}
In realtà nei sistemi unix esiste un'altro modo per definire la funzione
-\texttt{main}, che prevede la presenza di un terzo parametro, \texttt{char
+\func{main}, che prevede la presenza di un terzo parametro, \var{char
*envp[]}, che fornisce l'\textsl{ambiente} (vedi \secref{sec:proc_environ})
del programma; questa forma però non è prevista dallo standard POSIX.1 per cui
se si vogliono scrivere programmi portabili è meglio evitarla.
\subsection{Come chiudere un programma}
-\label{sec:proc_termination}
+\label{sec:proc_conclusion}
-La via normale per la quale un programma finisce è quando la funzione main
-ritorna, una modalità equivalente di conclusione è quella di chiamare
-direttamente la funzione \texttt{exit} (che viene comunque chiamata dalla
-routine di avvio del programma quando la funzione main ritorna). Una forma
-alternativa è quella di chiamare direttamente la system call \texttt{\_exit}
-che passa il controllo direttamente al kernel.
+La via normale per la quale un programma finisce è quando la funzione
+\func{main} ritorna, una modalità equivalente di conclusione è quella di
+chiamare direttamente la funzione \func{exit} (che viene comunque chiamata
+dalla routine di avvio del programma quando la funzione \func{main} ritorna).
+Una forma alternativa è quella di chiamare direttamente la system call
+\func{\_exit} che passa il controllo direttamente al kernel.
Oltre alla conclusione ``normale'' esiste anche la possibilità di una
conclusione ``anomala'' del programma a causa di segnali o della chiamata alla
-funzione \texttt{abort} (che comunque genera un segnale che termina il
-programma); torneremo su questo in \secref{sec:sig_prog_error}.
+funzione \func{abort} (che comunque genera un segnale che termina il
+programma); torneremo su questo in \secref{sec:proc_termination}.
Il valore di ritorno della funzione main, o quello usato nelle chiamate ad
-\texttt{exit} e \texttt{\_exit}, viene chiamato \textit{exit status} e passato
+\func{exit} e \func{\_exit}, viene chiamato \textit{exit status} e passato
al processo padre che aveva lanciato il programma (in genere la shell). In
generale si usa questo valore per fornire un'informazione generica sulla
riuscita o il fallimento del programma; l'informazione è necessariamente
In generale si usa la convenzione di restituire 0 in caso di successo e 1 in
caso di fallimento, i programmi che effettuano dei confronti (come
-\texttt{diff}) usano invece una notazione leggermente diversa, usando 0 per
+\cmd{diff}) usano invece una notazione leggermente diversa, usando 0 per
indicare la corrispondenza, 1 per indicare la non corrispondenza e 2 per
indicare l'incapacità di effettuare il confronto. È opportuno adottare una di
queste convenzioni a seconda dei casi. Si tenga presente che se si raggiunge
-la fine della funzione \texttt{main} senza ritornare esplicitamente si ha un
+la fine della funzione \func{main} senza ritornare esplicitamente si ha un
valore di uscita indefinito, è pertanto consigliabile di concludere sempre in
maniera esplicita detta funzione.
universalmente seguita è una buona idea tenerne conto.
Si tenga presente inoltre che non è una buona idea usare il valore dell'errore
-restituito dalla variabile \texttt{errno} come stato di uscita, in generale
+restituito dalla variabile \var{errno} come stato di uscita, in generale
una shell non si cura di tutto questo e comunque il valore dello stato di
uscita è sempre troncato ad 8 bit, per cui si potrebbe incorrere nel caso in
cui l'errore 256, diventando zero, verrebbe interpretato come un successo. In
-\texttt{stdlib.h} sono definite due macro \texttt{EXIT\_SUCCESS} e
-\texttt{EXIT\_FAILURE}, che in Linux sono poste rispettivamente ai valori 0 e
-1 (di tipo \texttt{int}), seguendo lo standard POSIX.
+\file{stdlib.h} sono definite due macro \macro{EXIT\_SUCCESS} e
+\macro{EXIT\_FAILURE}, che in Linux sono poste rispettivamente ai valori 0 e
+1 (di tipo \type{int}), seguendo lo standard POSIX.
Infine occorre distinguere fra lo stato di uscita di un programma
(l'\textit{exit status}) e lo stato di conclusione di un processo (il
possibile un processo possa essere terminato (da un segnale) prima che il
programma in esecuzione si sia concluso. In caso di conclusione normale del
programma però lo stato di uscita diventa parte dello stato di conclusione del
-processo (vedi \secref{sec:prochand_xxx}).
+processo (vedi \secref{sec:proc_termination}).
-\subsection{Le funzioni \texttt{exit} e \texttt{\_exit}}
+\subsection{Le funzioni \func{exit} e \func{\_exit}}
\label{sec:proc_exit}
Come accennato funzioni per l'uscita ``normale'' da un programma sono due, la
-prima è la funzione \texttt{exit} che è definita dallo standard ANSI C; il
+prima è la funzione \func{exit} che è definita dallo standard ANSI C; il
prototipo della funzione è il seguente:
\begin{prototype}{stdlib.h}{void exit(int status)}
Causa la conclusione ordinaria del programma restituendo il valore
- \texttt{status} al processo padre.
+ \var{status} al processo padre.
La funzione non ritorna. Il processo viene terminato
\end{prototype}
-La funzione \texttt{exit} è pensata per una conclusione pulita di un programma
+La funzione \func{exit} è pensata per una conclusione pulita di un programma
che usa le librerie standard del C; essa esegue tutte le funzioni che sono
-state registrate con \texttt{atexit} e \texttt{on\_exit} (vedi
+state registrate con \func{atexit} e \func{on\_exit} (vedi
\secref{sec:proc_atexit}), e chiude tutti gli stream di I/O effettuando il
-salvataggio dei dati sospesi (chiamando \texttt{fclose}, vedi
+salvataggio dei dati sospesi (chiamando \func{fclose}, vedi
\secref{sec:file_fclose}), infine ripassa il controllo al kernel chiamando
-\texttt{\_exit} e passando il valore \texttt{status} come stato di uscita.
+\func{\_exit} e passando il valore \var{status} come stato di uscita.
-La system call \texttt{\_exit} restituisce direttamente il controllo al
+La system call \func{\_exit} restituisce direttamente il controllo al
kernel, concludendo immediatamente il processo, le eventuali funzioni
-registrate con \texttt{atexit} e \texttt{on\_exit} non vengono eseguite. Il
+registrate con \func{atexit} e \func{on\_exit} non vengono eseguite. Il
prototipo della funzione è il seguente:
\begin{prototype}{unistd.h}{void \_exit(int status)}
Causa la conclusione immediata del programma restituendo il valore
- \texttt{status} al processo padre.
+ \var{status} al processo padre.
La funzione non ritorna. Il processo viene terminato.
\end{prototype}
La funzione chiude tutti i file descriptor appartenenti al processo (sui tenga
presente che questo non comporta il salvataggio dei dati bufferizzati degli
-stream), fa si che ogni figlio del processo sia ereditato da \texttt{init}
-(vedi \secref{cha:process_handling}), manda un segnale \texttt{SIGCHLD} al
+stream), fa si che ogni figlio del processo sia ereditato da \cmd{init}
+(vedi \secref{cha:process_handling}), manda un segnale \macro{SIGCHLD} al
processo padre (vedi \ref{sec:sig_job_control}) ed infine ritorna lo stato di
-uscita specificato in \texttt{status} che può essere raccolto usando la
-funzione \texttt{wait} (vedi \secref{sec:prochand_wait}).
+uscita specificato in \var{status} che può essere raccolto usando la
+funzione \func{wait} (vedi \secref{sec:proc_wait}).
-\subsection{Le funzioni \texttt{atexit} e \texttt{on\_exit}}
+\subsection{Le funzioni \func{atexit} e \func{on\_exit}}
\label{sec:proc_atexit}
-Come accennato l'uso di \texttt{exit} al posto della \texttt{\_exit} è fatto
+Come accennato l'uso di \func{exit} al posto della \func{\_exit} è fatto
principalmente per permettere una uscita pulita dalle funzioni delle librerie
standard del C (in particolare per quel che riguarda la chiusura degli
stream).
A questo scopo lo standard ANSI C prevede la possibilità di registrare un
certo numero funzioni che verranno eseguite all'uscita dal programma (sia per
-la chiamata ad \textit{exit} che per il ritorno di \texttt{main}). La prima
+la chiamata ad \func{exit} che per il ritorno di \func{main}). La prima
funzione che si può utilizzare a tal fine è:
\begin{prototype}{stdlib.h}{void atexit(void (*function)(void))}
- Registra la funzione \texttt{function} per essere chiamata all'uscita dal
+ Registra la funzione \var{function} per essere chiamata all'uscita dal
programma.
La funzione restituisce 0 in caso di successo e -1 in caso di fallimento,
La funzione richiede come argomento l'indirizzo della opportuna da chiamare
all'uscita che non deve prendere argomenti e non deve ritornare niente. Una
-estensione di \texttt{atexit} è la funzione \texttt{on\_exit} (che la glibc
+estensione di \func{atexit} è la funzione \func{on\_exit} (che la glibc
include per compatibilità con SunOS e che non è detto sia definita su altri
sistemi), il cui prototipo è:
\begin{prototype}{stdlib.h}
{void on\_exit(void (*function)(int status, void *arg), void *arg)}
- Registra la funzione \texttt{function} per essere chiamata all'uscita dal
+ Registra la funzione \var{function} per essere chiamata all'uscita dal
programma. Tutte le funzioni registrate vengono chiamate in ordine inverso
rispetto a quello di registrazione.
La funzione restituisce 0 in caso di successo e -1 in caso di fallimento,
- \texttt{errno} non viene settata.
+ \var{errno} non viene settata.
\end{prototype}
In questo caso la funzione da chiamare prende due parametri, il primo dei
quali sarà inizializzato allo stato di uscita con cui è stata chiamata
-\texttt{exit} ed il secondo al puntatore generico specificato come secondo
-argomento nella chiamata di \texttt{on\_exit}.
+\func{exit} ed il secondo al puntatore generico specificato come secondo
+argomento nella chiamata di \func{on\_exit}.
Nella sequenza di chiusura tutte le funzioni registrate verranno chiamate in
ordine inverso rispetto a quello di registrazione (ed una stessa funzione
registrata più volte sarà chiamata più volte); poi verranno chiusi tutti gli
-stream aperti, infine verrà chiamata \texttt{\_exit}.
+stream aperti, infine verrà chiamata \func{\_exit}.
\subsection{Conclusioni}
Data l'importanza dell'argomento è opportuno sottolineare ancora una volta che
in un sistema unix l'unico modo in cui un programma può essere eseguito dal
-kernel è attraverso la chiamata alla system call \texttt{execve} (in genere
-attraverso una delle funzioni \texttt{exec} che vedremo in
-\secref{sec:prochand_exec}).
+kernel è attraverso la chiamata alla system call \func{execve} (in genere
+attraverso una delle funzioni \func{exec} che vedremo in
+\secref{sec:proc_exec}).
Allo stesso modo l'unico modo in cui un programma può concludere
volontariamente la sua esecuzione è attraverso una chiamata alla system call
-\texttt{\_exit} sia esplicitamente o che in maniera indiretta attraverso l'uso
-di \texttt{exit} o il ritorno della funzione \texttt{main}.
+\func{\_exit} sia esplicitamente o che in maniera indiretta attraverso l'uso
+di \func{exit} o il ritorno della funzione \func{main}.
Lo schema delle modalità con cui si avvia e conclude normalmente un programma
è riportato in \nfig.
Lo stesso pezzo di memoria reale (o di spazio disco) può fare da supporto a
diverse pagine di memoria virtuale appartenenti a processi diversi (come
accade in genere per le pagine che contengono il codice delle librerie
-condivise). Ad esempio il codice della funzione \texttt{printf} starà su una
+condivise). Ad esempio il codice della funzione \func{printf} starà su una
sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria
virtuale di tutti i processi hanno detta funzione nel loro codice.
chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
scrivere da un indirizzo per il quale non esiste una associazione della pagina
virtuale il kernel risponde al relativo \textit{page fault}, mandando un
-segnale \texttt{SIGSEGV} al processo, che normalmente ne causa la terminazione
+segnale \macro{SIGSEGV} al processo, che normalmente ne causa la terminazione
immediata.
È pertanto importante capire come viene strutturata la memoria virtuale di un
utilizzarlo, e viene marcato in sola lettura per evitare sovrascritture
accidentali (o maliziose) che ne modifichino le istruzioni.
- Viene allocato da \texttt{exec} all'avvio del programma e resta invariato
+ Viene allocato da \func{exec} all'avvio del programma e resta invariato
per tutto il tempo dell'esecuzione.
\item Il segmento dei dati (\textit{data segment}). Contiene le variabili
double pi = 3.14;
\end{lstlisting}
questo valore sarà immagazzinato in questo segmento. La memoria di questo
- segmento viene preallocato dalla \texttt{exec} e inizializzata ai valori
+ segmento viene preallocato dalla \func{exec} e inizializzata ai valori
specificati.
La seconda parte è il segmento dei dati non inizializzati, che contiene le
\end{lstlisting}
questo valore sarà immagazzinato in questo segmento. Anch'esso viene
allocato all'avvio, e tutte le variabili vengono inizializzate a
- zero (ed i puntatori a \texttt{NULL}).
+ zero (ed i puntatori a \macro{NULL}).
Storicamente questo segmento viene chiamato BBS (da \textit{block started by
symbol}. La sua dimensione è fissa.
\end{figure}
Una disposizione tipica di questi segmenti è riportata in \nfig. Usando il
-comando \texttt{size} su un programma se ne può stampare le dimensioni dei
+comando \cmd{size} su un programma se ne può stampare le dimensioni dei
segmenti di testo e di dati (inizializzati e BSS); il BSS però non è mai
salvato sul file, in quanto viene inizializzato a zero al caricamento del
programma.
quella in cui vanno le variabili globali e le variabili statiche (e viene
effettuata nel segmento dei dati), lo spazio per queste variabili viene
allocati all'avvio del programma (come parte delle operazioni svolte da
-\texttt{exec}) e non viene liberato fino alla sua conclusione.
+\func{exec}) e non viene liberato fino alla sua conclusione.
L'allocazione automatica è quella che avviene per le cosiddette variabili
automatiche, cioè gli argomenti delle funzioni o le variabili locali. Lo
possano essere modificate durante l'esecuzione del programma; però le librerie
del C forniscono una serie opportuna di funzioni per permettere l'allocazione
dinamica di spazio in memoria (in genere nello heap, usando la system call
-\texttt{sbrk}), solo che a questo punto detto spazio sarà accessibile solo in
+\func{sbrk}), solo che a questo punto detto spazio sarà accessibile solo in
maniera indiretta attraverso dei puntatori.
-\subsection{Le funzioni \texttt{malloc}, \texttt{calloc}, \texttt{realloc} e
- \texttt{free}}
+\subsection{Le funzioni \func{malloc}, \func{calloc}, \func{realloc} e
+ \func{free}}
\label{sec:proc_mem_malloc}
Le funzioni previste dallo standard ANSI C per la gestione della memoria sono
\begin{functions}
\headdecl{stdlib.h}
\funcdecl{void *calloc(size\_t size)}
- Alloca \texttt{size} bytes nello heap. La memoria viene inizializzata a 0.
+ Alloca \var{size} byte nello heap. La memoria viene inizializzata a 0.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
- di successo e \texttt{NULL} in caso di fallimento, nel qual caso
- \texttt{errno} viene settata a \texttt{ENOMEM}.
+ di successo e \macro{NULL} in caso di fallimento, nel qual caso
+ \var{errno} viene settata a \macro{ENOMEM}.
\funcdecl{void *malloc(size\_t size)}
- Alloca \texttt{size} bytes nello heap. La memoria non viene inizializzata.
+ Alloca \var{size} byte nello heap. La memoria non viene inizializzata.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
- di successo e \texttt{NULL} in caso di fallimento, nel qual caso
- \texttt{errno} viene settata a \texttt{ENOMEM}.
+ di successo e \macro{NULL} in caso di fallimento, nel qual caso
+ \var{errno} viene settata a \macro{ENOMEM}.
\funcdecl{void *realloc(void *ptr, size\_t size)}
- Cambia la dimensione del blocco allocato all'indirizzo \texttt{ptr}
- portandola a \texttt{size}.
+ Cambia la dimensione del blocco allocato all'indirizzo \var{ptr}
+ portandola a \var{size}.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
- di successo e \texttt{NULL} in caso di fallimento, nel qual caso
- \texttt{errno} viene settata a \texttt{ENOMEM}.
+ di successo e \macro{NULL} in caso di fallimento, nel qual caso
+ \var{errno} viene settata a \macro{ENOMEM}.
\funcdecl{void free(void *ptr)}
- Disalloca lo spazio di memoria puntato da \texttt{ptr}.
+ Disalloca lo spazio di memoria puntato da \var{ptr}.
La funzione non ritorna nulla.
\end{functions}
macchine a 32 bit in genere è allineato a multipli di 4 byte e sulle macchine
a 64 bit a multipli di 8 byte.
-In genere su usano le funzioni \texttt{malloc} e \texttt{calloc} per allocare
+In genere su usano le funzioni \func{malloc} e \func{calloc} per allocare
dinamicamente la memoria necessaria al programma, siccome i puntatori
ritornati sono di tipo generico non è necessario effettuare un cast per
assegnarli a puntatori al tipo di variabile per la quale si effettua la
allocazione.
La memoria allocata dinamicamente deve essere esplicitamente rilasciata usando
-\texttt{free}\footnote{le glibc provvedono anche una funzione \texttt{cfree}
- defininita per compatibilità con SunOS, che è deprecata} una volta che non
+\func{free}\footnote{le glibc provvedono anche una funzione \func{cfree}
+ definita per compatibilità con SunOS, che è deprecata} una volta che non
sia più necessaria. Questa funzione vuole come parametro un puntatore
restituito da una precedente chiamata a una qualunque delle funzioni di
allocazione e che non sia già stato liberato da un'altra chiamata a
-\texttt{free}, in caso contrario il comportamento della funzione è indefinito.
+\func{free}, in caso contrario il comportamento della funzione è indefinito.
-La funzione \texttt{realloc} si usa invece per cambiare (in genere aumentare)
+La funzione \func{realloc} si usa invece per cambiare (in genere aumentare)
la dimensione di un'area di memoria precedentemente allocata, la funzione
vuole in ingresso il puntatore restituito dalla precedente chiamata ad una
-\texttt{malloc} (se è passato un valore \texttt{NULL} allora la funzione si
-comporta come \texttt{malloc}\footnote{questo è vero per linux e
+\func{malloc} (se è passato un valore \macro{NULL} allora la funzione si
+comporta come \func{malloc}\footnote{questo è vero per Linux e
l'implementazione secondo lo standard ANSI C, ma non è vero per alcune
vecchie implementazioni, inoltre alcune versioni delle librerie del C
- consentivano di usare \texttt{realloc} anche per un puntatore liberato con
- \texttt{free} purché non ci fossero state altre chiamate a funzioni di
+ consentivano di usare \func{realloc} anche per un puntatore liberato con
+ \func{free} purché non ci fossero state altre chiamate a funzioni di
allocazione, questa funzionalità è totalmente deprecata e non è consentita
- sotto linux}), ad esempio quando si deve far crescere la dimensione di un
+ sotto Linux}), ad esempio quando si deve far crescere la dimensione di un
vettore; in questo caso se è disponibile dello spazio adiacente al precedente
la funzione lo utilizza, altrimenti rialloca altrove un blocco della dimensione
voluta copiandoci automaticamente il contenuto, lo spazio in più non viene
ridimensionare.
Uno degli errori più comuni (specie se si ha a che fare con array di
-puntatori) è infatti quello di chiamare \texttt{free} più di una volta sullo
+puntatori) è infatti quello di chiamare \func{free} più di una volta sullo
stesso puntatore; per evitare questo problema una soluzione di ripiego è
-quella di assegnare sempre a \texttt{NULL} ogni puntatore liberato con
-\texttt{free}, dato che, quando il parametro è un puntatore nullo,
-\texttt{free} non esegue nessuna operazione.
+quella di assegnare sempre a \macro{NULL} ogni puntatore liberato con
+\func{free}, dato che, quando il parametro è un puntatore nullo,
+\func{free} non esegue nessuna operazione.
Linux e le glibc hanno una implementazione delle routine di allocazione che è
controllabile dall'utente attraverso alcune variabili di ambiente, in
particolare diventa possibile tracciare questo tipo di errori usando la
-variabile \texttt{MALLOC\_CHECK\_} che quando viene settata mette in uso una
+variabile \macro{MALLOC\_CHECK\_} che quando viene settata mette in uso una
versione meno efficiente delle funzioni, che però è più tollerante nei
-confronti di piccoli errori come quello di chiamate doppie a \texttt{free}; in
-particolare se la variabile è posta a zero gli errori vengono ignorati, se è
-posta ad 1 viene stampato un avviso sullo standard error e se
+confronti di piccoli errori come quello di chiamate doppie a \func{free}; in
+particolare:
+\begin{itemize*}
+\item se la variabile è posta a zero gli errori vengono ignorati.
+\item se è posta ad 1 viene stampato un avviso sullo \textit{standard error}
+ (vedi \secref{sec:file_stdfiles}).
+\item se è posta a 2 viene chiamata \func{abort}, che in genere causa
+ l'immediata conclusione del programma.
+\end{itemize*}
Il problema più comune e più difficile da tracciare che si incontra con
l'allocazione della memoria è però quando la memoria non più utilizzata non
\texttt{alloca} che invece che allocare la memoria nello heap usa lo il
segmento di stack della funzione corrente. La sintassi è identica:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
- Alloca \texttt{size} bytes nel segmento di stack della funzione chiamante.
+ Alloca \texttt{size} byte nel segmento di stack della funzione chiamante.
La memoria non viene inizializzata.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
non è possibile aumentare le dimensioni dello stack una volta chiamata una
funzione e quindi l'uso limita la portabilità dei programmi, inoltre se si
cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma un
-segnale di \textit{segmentation violation} analogo a quello che si avrebbe da
-una ricorsione infinita.
+segnale di \textit{segment violation} analogo a quello che si avrebbe da una
+ricorsione infinita.
Inoltre non è chiaramente possibile usare questa funzione per allocare memoria
che deve poi essere usata anche al di fuori della funzione in cui questa viene
Il controllo del flusso di un programma in genere viene effettuato con le
varie istruzioni del linguaggio C, la più bistrattata delle quali è il
-\texttt{goto}, ampiamente deprecato in favore di costrutti più puliti; esiste
+\func{goto}, ampiamente deprecato in favore di costrutti più puliti; esiste
però un caso in l'uso di questa istruzione porta all'implementazione più
efficiente, quello dell'uscita in caso di errore.
annidate occorre usare la funzione \func{longjump}.
+
+
+
\section{La gestione di parametri e opzioni}
\label{sec:proc_options}
Il passaggio dei parametri e delle variabili di ambiente dalla riga di comando
al singolo programma quando viene lanciato è effettuato attraverso le
-variabili \texttt{argc}, \texttt{argv} che vengono passate al programma
+variabili \var{argc}, \var{argv} che vengono passate al programma
come argomenti della funzione principale.
\subsection{Il formato dei parametri}
individuare le parole viene usato come separatore lo spazio (comportamento
modificabile attraverso il settaggio della variabile di ambiente IFS).
-Nella scansione viene costruito il vettore di puntatori \texttt{argv} inserendo
+Nella scansione viene costruito il vettore di puntatori \var{argv} inserendo
in successione il puntatore alla stringa costituente l'$n$-simo parametro; la
-variabile \texttt{argc} viene inizializzata al numero di parametri trovati, in
+variabile \var{argc} viene inizializzata al numero di parametri trovati, in
questo modo il primo parametro è sempre il nome del programma (vedi \nfig).
\subsection{La gestione delle opzioni}
In generale un programma unix riceve da linea di comando sia i parametri che
le opzioni, queste ultime sono standardizzate per essere riconosciute come
-tali: un elemento di \texttt{argv} che inizia con \texttt{-} e che non sia un
+tali: un elemento di \var{argv} che inizia con \texttt{-} e che non sia un
singolo \texttt{-} o \texttt{--} viene considerato un'opzione. In in genere
le opzioni sono costituite da una lettera preceduta dal meno e possono avere o
no un parametro associato; un comando tipico può essere cioè qualcosa del
\end{verbatim}
ed in questo caso le opzioni sono \texttt{m} ed \texttt{r}.
-Per gestire le opzioni all'interno dei parametri passati in \texttt{argv} le
-librerie standard del C forniscono la funzione \texttt{getopt} (accessibile
-includendo \texttt{unistd.h}), che ha il prototipo:
-\begin{verbatim}
-int getopt(int argc, char * const argv[], const char * optstring);
-\end{verbatim}
+Per gestire le opzioni all'interno dei parametri passati in \func{argv} le
+librerie standard del C forniscono la funzione \func{getopt} che ha il
+prototipo:
+\begin{prototype}{unistd.h}
+{int getopt(int argc, char * const argv[], const char * optstring)}
+La funzione esegue il parsing degli argomenti passati da linea di comando
+riconoscendo le possibili opzioni segnalate con \var{optstring}.
+
+Ritorna il carattere che segue l'opzione, \cmd{:} se manca un parametro
+all'opzione, \cmd{?} se l'opzione è sconosciuta, e -1 se non esistono altre
+opzioni.
+\end{prototype}
-Questa funzione prende come argomenti le due variabili \texttt{argc} e
-\texttt{argv} ed una stringa che indica quali sono le opzioni valide; la
+Questa funzione prende come argomenti le due variabili \var{argc} e
+\var{argv} ed una stringa che indica quali sono le opzioni valide; la
funzione effettua la scansione della lista dei parametri ricercando ogni
-stringa che comincia con \texttt{-} e ritorna ogni volta che trova una opzione
+stringa che comincia con \cmd{-} e ritorna ogni volta che trova una opzione
valida.
-La stringa \texttt{optstring} indica quali sono le opzioni riconosciute ed è
+La stringa \var{optstring} indica quali sono le opzioni riconosciute ed è
costituita da tutti i caratteri usati per identificare le singole opzioni, se
l'opzione ha un parametro al carattere deve essere fatto seguire un segno di
due punti \texttt{:} nel caso appena accennato ad esempio la stringa di
un'opzione non dichiarata in \texttt{optstring} viene ritornato un \texttt{?}
mentre se l'opzione non è seguita da un parametro viene ritornato un
\texttt{:} infine se viene incontrato il valore \texttt{--} la scansione viene
-considerata conclusa.
+considerata conclusa, anche se vi sono altri parametri che cominciano con
+\texttt{-}.
Quando la funzione trova un'opzione essa ritorna il valore numerico del
carattere, in questo modo si possono prendere le azioni relative usando un
case; la funzione inizializza inoltre alcune variabili globali:
-\begin{itemize}
-\item \texttt{char * optarg} contiene il puntatore alla stringa argomento
+\begin{itemize*}
+\item \var{char * optarg} contiene il puntatore alla stringa argomento
dell'opzione.
-\item \texttt{int optind} alla fine della scansione restituisce l'indice del
+\item \var{int optind} alla fine della scansione restituisce l'indice del
primo argomento che non è un'opzione.
-\item \texttt{int opterr} previene, se posto a zero, la stampa di un messaggio
+\item \var{int opterr} previene, se posto a zero, la stampa di un messaggio
di errore in caso di riconoscimento di opzioni non definite.
-\item \texttt{int optopt} contiene il carattere dell'opzione non riconosciuta.
-\end{itemize}
-
-In \nfig\ è mostrato un programma di esempio,
+\item \var{int optopt} contiene il carattere dell'opzione non riconosciuta.
+\end{itemize*}
+In \nfig\ è mostrato un programma di esempio:
\begin{figure}[htbp]
\footnotesize
\begin{lstlisting}{}
exit(1);
}
break;
- break;
case 'a': /* output file (append) */
out_file=open(optarg,O_WRONLY|O_CREAT|O_APPEND);
break;
\label{fig:proc_options_code}
\end{figure}
+
\subsection{Opzioni in formato esteso}
\label{sec:proc_opt_extended}
Un'estensione di questo schema è costituito dalle cosiddette
\textit{long-options} espresse nella forma \texttt{--option=parameter}, anche
la gestione di queste ultime è stata standardizzata attraverso l'uso di una
-versione estesa di \texttt{getopt}.
+versione estesa di \func{getopt}.
+
+(NdA: da finire).
\subsection{Le variabili di ambiente}
chiamata ad \func{exec} che lo ha lanciato.
Come per la lista dei parametri anche questa lista è un array di puntatori a
-caratteri, ciascuno dei quali punta ad una stringa (terminata da un null). A
+caratteri, ciascuno dei quali punta ad una stringa (terminata da un NULL). A
differenza di \var{argv[]} però in questo caso non si ha la lunghezza
dell'array dato da un equivalente di \var{argc}, ma la lista è terminata da un
puntatore nullo.
in \curfig, sono definite dal sistema per queste c'è la convezione di usare
nomi espressi in caratteri maiuscoli.
-Il kernel non usa mai queste variabili, il loro uso e la loro intepretazione è
+Il kernel non usa mai queste variabili, il loro uso e la loro interpretazione è
riservata alle applicazioni e ad alcune funzioni di libreria; in genere esse
costituiscono un modo comodo per definire un comportamento specifico senza
dover ricorrere all'uso di opzioni a linea di comando o di file di
Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più
comuni), come riportato in \ntab. GNU/Linux le supporta tutte e ne definisce
-anche altre per una lista parziale si può controllare \cmd{man environ}
+anche altre per una lista parziale si può controllare \cmd{man environ}.
+
+
+
+