+%% process.tex
+%%
+%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to
+%% copy, distribute and/or modify this document under the terms of the GNU Free
+%% Documentation License, Version 1.1 or any later version published by the
+%% Free Software Foundation; with the Invariant Sections being "Prefazione",
+%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
\chapter{L'interfaccia base con i processi}
\label{cha:process_interface}
incorrere nel caso in cui restituendo un codice di errore 256, si otterrebbe
uno stato di uscita uguale a zero, che verrebbe interpretato come un successo.
-In \file{stdlib.h} sono definite, seguendo lo standard POSIX, le due macro
-\macro{EXIT\_SUCCESS} e \macro{EXIT\_FAILURE}, da usare sempre per specificare
+In \file{stdlib.h} sono definite, seguendo lo standard POSIX, le due costanti
+\const{EXIT\_SUCCESS} e \const{EXIT\_FAILURE}, da usare sempre per specificare
lo stato di uscita di un processo. In Linux esse sono poste rispettivamente ai
valori di tipo \ctyp{int} 0 e 1.
La funzione chiude tutti i file descriptor appartenenti al processo (si tenga
presente che questo non comporta il salvataggio dei dati bufferizzati degli
stream), fa sì che ogni figlio del processo sia ereditato da \cmd{init} (vedi
-\secref{cha:process_handling}), manda un segnale \macro{SIGCHLD} al processo
+\secref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
padre (vedi \secref{sec:sig_job_control}) ed infine ritorna lo stato di uscita
specificato in \param{status} che può essere raccolto usando la funzione
\func{wait} (vedi \secref{sec:proc_wait}).
chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
scrivere da un indirizzo per il quale non esiste un'associazione della pagina
virtuale, il kernel risponde al relativo \textit{page fault}\index{page fault}
-mandando un segnale \macro{SIGSEGV} al processo, che normalmente ne causa la
+mandando un segnale \const{SIGSEGV} al processo, che normalmente ne causa la
terminazione immediata.
È pertanto importante capire come viene strutturata \textsl{la memoria
\end{lstlisting}
questo vettore sarà immagazzinato in questo segmento. Anch'esso viene
allocato all'avvio, e tutte le variabili vengono inizializzate a zero (ed i
- puntatori a \macro{NULL}).\footnote{si ricordi che questo vale solo per le
+ puntatori a \val{NULL}).\footnote{si ricordi che questo vale solo per le
variabili che vanno nel segmento dati, e non è affatto vero in generale.}
Storicamente questo segmento viene chiamato BBS (da \textit{block started by
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 \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *malloc(size\_t size)}
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 \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *realloc(void *ptr, size\_t 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 \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void free(void *ptr)}
Disalloca lo spazio di memoria puntato da \var{ptr}.
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 \func{malloc} e \func{calloc} per allocare
-dinamicamente la memoria necessaria al programma, e 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
-l'allocazione.
+In genere si usano le funzioni \func{malloc} e \func{calloc} per allocare
+dinamicamente la quantità di memoria necessaria al programma indicata da
+\param{size},\footnote{queste funzioni presentano un comportamento diverso fra
+ le \acr{glibc} e le \acr{uClib} quando il valore di \param{size} è nullo.
+ Nel primo caso viene comunque restituito un puntatore valido, anche se non è
+ chiaro a cosa esso possa fare riferimento, nel secondo caso viene restituito
+ \val{NULL}. Il comportamento è analogo con \code{realloc(NULL, 0)}.} e
+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 l'allocazione.
La memoria allocata dinamicamente deve essere esplicitamente rilasciata usando
\func{free}\footnote{le glibc provvedono anche una funzione \func{cfree}
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
-\func{malloc} (se è passato un valore \macro{NULL} allora la funzione si
+\func{malloc} (se è passato un valore \val{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
Un errore abbastanza frequente (specie se si ha a che fare con array di
puntatori) è 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 \macro{NULL} ogni puntatore liberato con \func{free}, dato
+assegnare sempre a \val{NULL} ogni puntatore liberato con \func{free}, dato
che, quando il parametro è un puntatore nullo, \func{free} non esegue nessuna
operazione.
Le \acr{glibc} hanno un'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 \macro{MALLOC\_CHECK\_} che quando viene definita mette in uso una
-versione meno efficiente delle funzioni suddette, che però è più tollerante
-nei confronti di piccoli errori come quello di chiamate doppie a \func{free}.
-In particolare:
-\begin{itemize*}
+variabile d'ambiente \val{MALLOC\_CHECK\_} che quando viene definita mette in
+uso una versione meno efficiente delle funzioni suddette, che però è più
+tollerante nei 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_std_stream}).
\item se è posta a 2 viene chiamata \func{abort}, che in genere causa
l'immediata conclusione del programma.
-\end{itemize*}
+\end{itemize}
Il problema più comune e più difficile da risolvere che si incontra con le
routine di allocazione è quando non viene opportunamente liberata la memoria
non più utilizzata, quello che in inglese viene chiamato \textit{memory-leak},
-cioè \textsl{perdita di memoria}.
+cioè una \textsl{perdita di memoria}.
Un caso tipico che illustra il problema è quello in cui in una subroutine si
alloca della memoria per uso locale senza liberarla prima di uscire. La
che contiene l'errore. Per questo motivo è sempre molto difficile trovare un
\textit{memory leak}.
-Per ovviare a questi problemi l'implementazione delle routine di allocazione
-delle \acr{glibc} mette a disposizione una serie di funzionalità che
-permettono di tracciare le allocazioni e le disallocazione, e definisce anche
-una serie di possibili \textit{hook} (\textsl{ganci}) che permettono di
-sostituire alle funzioni di libreria una propria versione (che può essere più
-o meno specializzata per il debugging).
+In C e C++ il problema è particolarmente sentito. In C++, per mezzo della
+programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente
+ridimensionato attraverso l'uso accurato di appositi oggetti come gli
+\textit{smartpointers}. Questo però va a scapito delle performance
+dell'applicazione in esecuzione.
+
+In altri linguaggi come il java e recentemente il C\# il problema non si pone
+nemmeno perché la gestione della memoria viene fatta totalmente in maniera
+automatica, ovvero il programmatore non deve minimamente preoccuparsi di
+liberare la memoria allocata precedentemente quando non serve più, poiché il
+framework gestisce automaticamente la cosiddetta \textit{garbage collection}.
+In tal caso, attraverso meccanismi simili a quelli del \textit{reference
+ counting}, quando una zona di memoria precedentemente allocata non è più
+riferita da nessuna parte del codice in esecuzione, può essere deallocata
+automaticamente in qualunque momento dall'infrastruttura.
+
+Anche questo va a scapito delle performance dell'applicazione in esecuzione
+(inoltre le applicazioni sviluppate con tali linguaggi di solito non sono
+eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria
+la presenza di una infrastruttura per la loro interpretazione e pertanto hanno
+di per sé delle performance più scadenti rispetto alle stesse applicazioni
+compilate direttamente). Questo comporta però il problema della non
+predicibilità del momento in cui viene deallocata la memoria precedentemente
+allocata da un oggetto.
+
+Per limitare l'impatto di questi problemi, e semplificare la ricerca di
+eventuali errori, l'implementazione delle routine di allocazione delle
+\acr{glibc} mette a disposizione una serie di funzionalità che permettono di
+tracciare le allocazioni e le disallocazione, e definisce anche una serie di
+possibili \textit{hook} (\textsl{ganci}) che permettono di sostituire alle
+funzioni di libreria una propria versione (che può essere più o meno
+specializzata per il debugging). Esistono varie librerie che forniscono dei
+sostituti opportuni delle routine di allocazione in grado, senza neanche
+ricompilare il programma,\footnote{esempi sono \textit{Dmalloc}
+ \href{http://dmalloc.com/}{http://dmalloc.com/} di Gray Watson ed
+ \textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche
+molto complesse riguardo l'allocazione della memoria.
+
\subsection{La funzione \func{alloca}}
\label{sec:proc_mem_alloca}
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
-problemi di memory leak descritti in precedenza, è la funzione \func{alloca},
-che invece di allocare la memoria nello heap usa il segmento di stack della
-funzione corrente. La sintassi è identica a quella di \func{malloc}, il suo
-prototipo è:
+problemi di \textit{memory leak} descritti in precedenza, è la funzione
+\func{alloca}, che invece di allocare la memoria nello heap usa il segmento di
+stack della funzione corrente. La sintassi è identica a quella di
+\func{malloc}, il suo prototipo è:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
Alloca \var{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
- di successo e \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\end{prototype}
\noindent ma in questo caso non è più necessario liberare la memoria (e quindi
non esiste un analogo della \func{free}) in quanto essa viene rilasciata
\var{end\_data\_segment}.
La funzione restituisce 0 in caso di successo e -1 in caso di
- fallimento, nel qual caso \var{errno} assumerà il valore \macro{ENOMEM}.
+ fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *sbrk(ptrdiff\_t increment)} Incrementa lo spazio dati di un
programma di \var{increment}. Un valore zero restituisce l'attuale posizione
della fine del segmento dati.
La funzione restituisce il puntatore all'inizio della nuova zona di memoria
- allocata in caso di successo e \macro{NULL} in caso di fallimento, nel qual
- caso \macro{errno} assumerà il valore \macro{ENOMEM}.
+ allocata in caso di successo e \val{NULL} in caso di fallimento, nel qual
+ caso \var{errno} assumerà il valore \errval{ENOMEM}.
\end{functions}
\noindent in genere si usa \func{sbrk} con un valore zero per ottenere
l'attuale posizione della fine del segmento dati.
Queste funzioni sono state deliberatamente escluse dallo standard POSIX.1 e
per i programmi normali è sempre opportuno usare le funzioni di allocazione
standard descritte in precedenza, che sono costruite su di esse. L'uso di
-queste funzione è ristretto alle specifiche necessità di chi debba
+queste funzioni è ristretto alle specifiche necessità di chi debba
implementare una sua versione delle routine di allocazione.
Il \textit{memory lock} persiste fintanto che il processo che detiene la
memoria bloccata non la sblocca. Chiaramente la terminazione del processo
comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di
-tutti i suoi \textit{memory lock}.
-
-I \textit{memory lock} non sono ereditati dai processi figli.\footnote{ma
- siccome Linux usa il \textit{copy on write}\index{copy on write} (vedi
- \secref{sec:proc_fork}) gli indirizzi virtuali del figlio sono mantenuti
- sullo stesso segmento di RAM del padre, quindi fintanto che un figlio non
- scrive su un segmento, può usufruire del memory lock del padre.} Siccome la
-presenza di un \textit{memory lock} riduce la memoria disponibile al sistema,
-con un impatto su tutti gli altri processi, solo l'amministratore ha la
-capacità di bloccare una pagina. Ogni processo può però sbloccare le pagine
+tutti i suoi \textit{memory lock}. Infine \textit{memory lock} non sono
+ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on
+ write}\index{copy on write} (vedi \secref{sec:proc_fork}) gli indirizzi
+ virtuali del figlio sono mantenuti sullo stesso segmento di RAM del padre,
+ quindi fintanto che un figlio non scrive su un segmento, può usufruire del
+ memory lock del padre.}
+
+Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce
+la memoria fisica disponibile nel sistema, questo ha un evidente impatto su
+tutti gli altri processi, per cui solo un processo con i privilegi di
+amministratore (vedremo in \secref{sec:proc_perms} cosa significa) ha la
+capacità di bloccare una pagina. Ogni processo può però sbloccare le pagine
relative alla propria memoria.
Il sistema pone dei limiti all'ammontare di memoria di un processo che può
-essere bloccata e al totale di memoria fisica che può dedicare a questo, lo
-standard POSIX.1 richiede che sia definita in \file{unistd.h} la costante
+essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo
+standard POSIX.1 richiede che sia definita in \file{unistd.h} la macro
\macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il
-\textit{memory locking} e la costante \macro{PAGESIZE} in \file{limits.h} per
+\textit{memory locking} e la costante \const{PAGESIZE} in \file{limits.h} per
indicare la dimensione di una pagina in byte.
Le funzioni per bloccare e sbloccare singole sezioni di memoria sono
caso di errore, nel qual caso \var{errno} assumerà uno dei
valori seguenti:
\begin{errlist}
- \item[\macro{ENOMEM}] alcuni indirizzi dell'intervallo specificato non
+ \item[\errcode{ENOMEM}] alcuni indirizzi dell'intervallo specificato non
corrispondono allo spazio di indirizzi del processo o si è ecceduto
il numero massimo consentito di pagine bloccate.
- \item[\macro{EINVAL}] \var{len} non è un valore positivo.
+ \item[\errcode{EINVAL}] \var{len} non è un valore positivo.
\end{errlist}
- e, per \func{mlock}, anche \macro{EPERM} quando il processo non ha i
+ e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i
privilegi richiesti per l'operazione.}
\end{functions}
comportamento; esso può essere specificato come l'OR aritmetico delle due
costanti:
\begin{basedescript}{\desclabelwidth{2.5cm}}
-\item[\macro{MCL\_CURRENT}] blocca tutte le pagine correntemente mappate nello
+\item[\const{MCL\_CURRENT}] blocca tutte le pagine correntemente mappate nello
spazio di indirizzi del processo.
-\item[\macro{MCL\_FUTURE}] blocca tutte le pagine che saranno mappate nello
+\item[\const{MCL\_FUTURE}] blocca tutte le pagine che saranno mappate nello
spazio di indirizzi del processo.
\end{basedescript}
cosicché alla fine della scansione gli elementi che non sono opzioni sono
spostati in coda al vettore. Oltre a questa esistono altre due modalità di
gestire gli elementi di \var{argv}; se \var{optstring} inizia con il carattere
-\texttt{'+'} (o è impostata la variabile di ambiente \macro{POSIXLY\_CORRECT})
+\texttt{'+'} (o è impostata la variabile di ambiente \val{POSIXLY\_CORRECT})
la scansione viene fermata non appena si incontra un elemento che non è
un'opzione. L'ultima modalità, usata quando un programma può gestire la
mescolanza fra opzioni e argomenti, ma se li aspetta in un ordine definito, si
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
-\macro{NULL}. A differenza di \var{argv[]} in questo caso non si ha una
+\val{NULL}. A differenza di \var{argv[]} in questo caso non si ha una
lunghezza dell'array data da un equivalente di \var{argc}, ma la lista è
terminata da un puntatore nullo.
\end{figure}
Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo
-\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate
+\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate
in \figref{fig:proc_envirno_list}, sono definite dal sistema per essere usate
da diversi programmi e funzioni: per queste c'è l'ulteriore convenzione di
-usare nomi espressi in caratteri maiuscoli.
+usare nomi espressi in caratteri maiuscoli.\footnote{la convenzione vuole che
+ si usino dei nomi maiuscoli per le variabili di ambiente di uso generico, i
+ nomi minuscoli sono in genere riservati alle variabili interne degli script
+ di shell.}
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
-configurazione.
+configurazione. É di norma cura della shell, quando esegue un comando, passare
+queste variabili al programma messo in esecuzione attraverso un uso opportuno
+delle relative chiamate (si veda \secref{sec:proc_exec}).
La shell ad esempio ne usa molte per il suo funzionamento (come \var{PATH} per
la ricerca dei comandi, o \cmd{IFS} per la scansione degli argomenti), e
& \textbf{Linux} & \textbf{Descrizione} \\
\hline
\hline
- \macro{USER} & $\bullet$ & $\bullet$ & $\bullet$ & Nome utente\\
- \macro{LOGNAME} & $\bullet$ & $\bullet$ & $\bullet$ & Nome di login\\
- \macro{HOME} & $\bullet$ & $\bullet$ & $\bullet$ &
+ \val{USER} & $\bullet$ & $\bullet$ & $\bullet$ & Nome utente\\
+ \val{LOGNAME} & $\bullet$ & $\bullet$ & $\bullet$ & Nome di login\\
+ \val{HOME} & $\bullet$ & $\bullet$ & $\bullet$ &
Directory base dell'utente\\
- \macro{LANG} & $\bullet$ & $\bullet$ & $\bullet$ & Localizzazione\\
- \macro{PATH} & $\bullet$ & $\bullet$ & $\bullet$ & Elenco delle directory
- dei programmi\\
- \macro{PWD} & $\bullet$ & $\bullet$ & $\bullet$ & Directory corrente\\
- \macro{SHELL} & $\bullet$ & $\bullet$ & $\bullet$ & Shell in uso\\
- \macro{TERM} & $\bullet$ & $\bullet$ & $\bullet$ & Tipo di terminale\\
- \macro{PAGER} & $\bullet$ & $\bullet$ & $\bullet$ & Programma per vedere i
- testi\\
- \macro{EDITOR} & $\bullet$ & $\bullet$ & $\bullet$ & Editor preferito\\
- \macro{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser preferito\\
+ \val{LANG} & $\bullet$ & $\bullet$ & $\bullet$ & Localizzazione\\
+ \val{PATH} & $\bullet$ & $\bullet$ & $\bullet$ & Elenco delle directory
+ dei programmi\\
+ \val{PWD} & $\bullet$ & $\bullet$ & $\bullet$ & Directory corrente\\
+ \val{SHELL} & $\bullet$ & $\bullet$ & $\bullet$ & Shell in uso\\
+ \val{TERM} & $\bullet$ & $\bullet$ & $\bullet$ & Tipo di terminale\\
+ \val{PAGER} & $\bullet$ & $\bullet$ & $\bullet$ & Programma per vedere i
+ testi\\
+ \val{EDITOR} & $\bullet$ & $\bullet$ & $\bullet$ & Editor preferito\\
+ \val{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser preferito\\
+ \val{TMPDIR} & $\bullet$ & $\bullet$ & $\bullet$ & Directory dei file
+ temporanei\\
\hline
\end{tabular}
- \caption{Variabili di ambiente più comuni definite da vari standard.}
+ \caption{Esempi di variabili di ambiente più comuni definite da vari
+ standard.}
\label{tab:proc_env_var}
\end{table}
-Lo standard ANSI C prevede l'esistenza di un ambiente, pur non entrando nelle
-specifiche di come sono strutturati i contenuti, e definisce la funzione
-\func{getenv} che permette di ottenere i valori delle variabili di ambiente,
-il cui prototipo è:
+Lo standard ANSI C prevede l'esistenza di un ambiente, e pur non entrando
+nelle specifiche di come sono strutturati i contenuti, definisce la funzione
+\func{getenv} che permette di ottenere i valori delle variabili di ambiente;
+il suo prototipo è:
\begin{prototype}{stdlib.h}{char *getenv(const char *name)}
Esamina l'ambiente del processo cercando una stringa che corrisponda a
quella specificata da \param{name}.
- \bodydesc{La funzione ritorna \macro{NULL} se non trova nulla, o il
+ \bodydesc{La funzione ritorna \val{NULL} se non trova nulla, o il
puntatore alla stringa che corrisponde (di solito nella forma
\cmd{NOME=valore}).}
\end{prototype}
\label{tab:proc_env_func}
\end{table}
-In Linux solo le prime quattro funzioni di \tabref{tab:proc_env_func} sono
-definite, \func{getenv} l'abbiamo già esaminata; delle tre restanti le prime
-due, \func{putenv} e \func{setenv}, servono per assegnare nuove variabili di
-ambiente, i loro prototipi sono i seguenti:
+In Linux sono definite solo le prime quattro delle funzioni elencate in
+\tabref{tab:proc_env_func}. La prima, \func{getenv}, l'abbiamo appena
+esaminata; delle tre restanti le prime due, \func{putenv} e \func{setenv},
+servono per assegnare nuove variabili di ambiente, i loro prototipi sono i
+seguenti:
\begin{functions}
\headdecl{stdlib.h}
all'ambiente.
\bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 per un
- errore, che è sempre \macro{ENOMEM}.}
+ errore, che è sempre \errval{ENOMEM}.}
\end{functions}
\noindent la terza, \func{unsetenv}, serve a cancellare una variabile di
ambiente; il suo prototipo è:
macro; la procedura da seguire è la seguente:
\begin{enumerate*}
\item Inizializzare un puntatore alla lista degli argomenti di tipo
- \type{va\_list} attraverso la macro \macro{va\_start}.
+ \macro{va\_list} attraverso la macro \macro{va\_start}.
\item Accedere ai vari argomenti opzionali con chiamate successive alla macro
\macro{va\_arg}, la prima chiamata restituirà il primo argomento, la seconda
il secondo e così via.
Una modalità diversa, che può essere applicata solo quando il tipo dei
parametri lo rende possibile, è quella che prevede di usare un valore speciale
come ultimo argomento (come fa ad esempio \func{execl} che usa un puntatore
-\macro{NULL} per indicare la fine della lista degli argomenti).
+\val{NULL} per indicare la fine della lista degli argomenti).
\subsection{Potenziali problemi con le variabili automatiche}