269x Filetype PDF File size 1.47 MB Source: www.riochierego.it
LINGUAGGIO C ANSI C Brian W. Kernighan Dennis M. Ritchie PREFAZIONE Con la pubblicazione del volume Linguaggio C, il mondo dei calcolatori ha subito un profondo mutamento. I grandi calcolatori crescono sempre più, ed i personal computer hanno capacità paragonabili a quelle dei mainframe di una decina di anni fa. In questo periodo anche il C è cambiato, anche se di poco, e si è esteso ben oltre i limiti delle sue origini, che lo identificavano semplicemente come il linguaggio del sistema operativo UNIX. La crescente popolarità del C, le modifiche che ha subito nel corso degli anni e la nascita di compilatori scritti da gruppi che non hanno partecipato alla sua stesura originale concorrono a dimostrare la necessità di una definizione del linguaggio più precisa ed attuale di quella fornita nella prima edizione di questo libro. Nel 1983, l'Istituto Nazionale Americano per gli Standard (ANSI) ha costituito un comitato per "una defi-nizione del linguaggio C non ambigua e non dipendente dalla macchina". Il risultato di questa ricerca è lo standard ANSI per il C. Lo standard formalizza alcune interpretazioni suggerite, ma non descritte, nella prima edizione quali, per esempio, l'assegnamento fra strutture ed i tipi enumerativi. Esso fornisce una nuova forma di definizione della funzione, che consente il controllo incrociato della definizione stessa e delle chiamate. Specifica, inoltre, una libreria standard, con un insieme esteso di funzioni per l’input / output, la gestione della memoria, la manipolazione di stringhe ed attività affini. Lo standard specifica il comportamento di funzionalità formalizzate in modo incompleto nella prima edizione e, contemporaneamente, stabilisce esplicitamente quali aspetti del linguaggio rimangono dipendenti dalla macchina. Questa seconda edizione de Linguaggio C descrive il C definito dall’ANSI (al momento della stesura del libro, lo standard si trovava in fase di revisione finale; si pensa che venga approvato verso la fine del 1988. Le differenze tra quanto descritto nel seguito e la versione definitiva dello standard dovrebbero essere minime). Pur avendo rilevato gli aspetti nei quali il linguaggio si è evoluto, abbiamo preferito riportare soltanto la nuova versione. Nella maggior parte dei casi, ciò non dovrebbe comportare differenze significative; il cambiamento più evidente consiste nell’introduzione della nuova forma di dichiarazione e definizione di funzione. I compilatori più recenti supportano già molte funzionalità dello standard. Abbiamo cercato di mantenere la sinteticità della prima edizione: il C non è un linguaggio molto vasto, ed un libro voluminoso non gli si addice. Abbiamo approfondito l’esposizione di funzionalità critiche, quali i puntatori, fondamentali per la programmazione in C. Abbiamo migliorato alcuni degli esempi originali, ed in alcuni capitoli ne abbiamo aggiunti di nuovi: il trattamento delle dichiarazioni complesse viene completato con la presentazione di programmi che convertono dichiarazioni in frasi e viceversa. Inoltre, tutti gli esempi sono stati provati direttamente nella forma presentata nel testo. L’Appendice A, il manuale di riferimento, non è lo standard, bensì il risultato del nostro tentativo di convo- gliare le caratteristiche essenziali dello standard in uno spazio più ristretto. Questo manuale è stato concepito per essere facilmente compreso dai programmatori, e non come definizione per i progettisti di compilatori (questo ruolo spetta allo standard stesso). L’Appendice B è un sommario delle funzionalità della libreria standard. Anch’essa dev’essere intesa come manuale di riferimento per i programmatori, non per i progettisti. L’Appendice C è un conciso elenco delle variazioni rispetto alla versione originale. Come abbiamo detto nella prefazione alla prima edizione, il C ben si adatta ad un’esperienza in crescita e, dopo dieci anni di attività sul C, noi siamo ancora convinti che ciò sia vero. Speriamo che questo libro vi aiuti ad imparare il C e vi insegni ad usarlo bene. Siamo profondamente grati agli amici che ci hanno aiutato a produrre questa seconda edizione. Jon Bentley, Doug McIlroy, Peter Nelson e Robe Pike hanno formulato commenti costruttivi su quasi ogni singola pagina del manoscritto. Siamo grati, per la loro attenta lettura, ad Al Aho, Dennis Allison, Joe Campbell, G. R. Emlin, Karen Fortgang, Allen Holub, Andrew Hume, Dave Kristol, John Linderman, Dave Prosser, Gene Spafford e Chris Van Wyk. Abbiamo ricevuto suggerimenti utili anche da Bill Cheswick, Mark Kernighan, Andy Koenig, Robin Lake, Tom London, Jim Reeds, Clovis Tondo e Peter Weinberger. Dave Prosser ha risposto a molte domande dettagliate sullo standard ANSI. Abbiamo usato molto il traduttore C++ di Bjarne Stroustrup per il testing locale dei nostri programmi, e Dave Kristol ci ha fornito un compilatore ANSI C per il testing finale. Rich Dreschler ci ha aiutato nella composizione. A tutti, i nostri più sinceri ringraziamenti. Brian W. Kernighan Dennis M. Ritchie PREFAZIONE ALLA PRIMA EDIZIONE Il C è un linguaggio di programmazione di uso generale, caratterizzato dalla sinteticità, da un controllo del flusso e da strutture dati avanzate, e da un vasto insieme di operatori. Il C non è un vero “linguaggio ad alto livello”, e non è specializzato in alcun’area applicativa. Ma il suo essere privo di restrizioni e la sua generalità lo rendono spesso più conveniente ed efficiente di altri linguaggio supposti più potenti. In origine, il C è stato progettato ed implementato da Dennis Ritchie su un sistema operativo UNIX, su un calcolatore DEC PDP-11. Il sistema operativo, il compilatore C ed essenzialmente tutti i programmi applica- tivi di UNIX (compreso il software utilizzato per preparare questo libro) sono scritti in C. Esistono anche compilatori per altre macchine, fra le quali il Sistema / 370 IBM, l’Honeywell 6000 e l’Interdata 8/32. Tuttavia, il C non è progettato per alcun hardware o sistema particolare, ed è facile scrivere programmi funzionanti, senza bisogno di alcuna modifica, su tutti i sistemi che supportano il C. Questo libro si propone di insegnare al lettore come programmare in C. Esso contiene un’introduzione di carattere generale, alcuni capitoli relativi alle principali funzionalità ed un manuale di riferimento. La maggior parte della trattazione si basa sulla lettura, la scrittura e la revisione degli esempi, più che sulla semplice esposizione delle regole. Quasi sempre gli esempi sono costituiti non da frammenti isolati di codice, ma da programmi completi. Inoltre, tutti gli esempi sono stati provati direttamente nella forma presentata nel testo. Oltre che mostrare l’uso effettivo del linguaggio abbiamo cercato, ove possibile, di fornire algoritmi utili ed alcuni dei principi che stanno alla base di una buona metodologia di stesura del codice. Il libro non è un manuale di introduzione alla programmazione; in esso assumiamo che il lettore possieda un certo grado di familiarità con alcuni concetti basilari, quali le variabili, le istruzioni di assegnamento, i cicli e le funzioni. Ciò nonostante, un programmatore principiante dovrebbe essere in grado di leggere il libro ed apprendere il linguaggio, magari con l’aiuto di un collega più esperto. La nostra esperienza personale ci ha dimostrato che il C è un linguaggio piacevole, espressivo e versatile. Esso è facile da apprendere, e ben si adatta ad un’esperienza in crescita. Speriamo che questo libro vi aiuti ad imparare il C e vi insegni ad usarlo bene. Le critiche costruttive ed i suggerimenti di molti amici hanno migliorato notevolmente questo libro, ed aumentato il nostro piacere nello scriverlo. In particolare, Mike Bianchi, Jim Blue, Stu Feldman, Doug McIlroy, Bill Roome, Bob Rosin e Larry Rosler hanno letto con attenzione molte versioni dell’opera. Siamo anche riconoscenti ad Al Aho, Steve Bourne, Dan Dvorak, Chuck Haley, Debbie Haley, Marion Harris, Rick Holt, Steve Johnson, John Mashey, Bob Mitze, Ralph Muha, Peter Nelson, Elliot Pinson, Bill Plauger, Jerry Spivack, Ken Thompson e Peter Weinberger per gli utili commenti, e, infine, ringraziamo Mike Lesk e Joe Ossanna per il loro indispensabile aiuto nella composizione del libro. Brian W. Kernighan Dennis M. Ritchie INTRODUZIONE Il C è un linguaggio di programmazione di uso generale da sempre strettamente legato al sistema UNIX, sul quale è stato sviluppato, poiché sia il sistema che la maggior parte dei suoi programmi applicativi sono scritti in C. Tuttavia, questo linguaggio non è stato scritto per un particolare sistema operativo o per una particolare macchina; sebbene sia stato definito un “linguaggio di programmazione di sistema” perché adatto alla stesura di compilatori e sistemi operativi, è stato impiegato con profitto nella realizzazione di grossi programmi operanti negli ambienti più disparati. Molte delle caratteristiche del C discendono dal linguaggio BCPL, sviluppato da Martin Richards. L’influenza del BCPL sul C passa, indirettamente, dal linguaggio B, ideato da Thompson nel 1970 per il primo sistema UNIX, sviluppato su DEC PDP-7. I linguaggi BCPL e B sono linguaggi senza tipi. Al contrario, il C fornisce numerosi tipi di dati. I tipi fonda- mentali sono i caratteri ed i numeri interi e decimali. Oltre a questi, esiste un vasto insieme di tipi di dati derivati, creati usando puntatori, vettori, strutture e union. Le espressioni sono formate da operatori ed ope- randi; qualsiasi espressione, compreso un assegnamento o una chiamata di funzione, può essere un’istru- zione. I puntatori consentono poi un’aritmetica di indirizzamento indipendente dalla macchina. Il C fornisce i fondamentali costrutti per il controllo del flusso, indispensabili per la stesura di programmi ben strutturati; tali costrutti sono: il raggruppamento delle istruzioni, il blocco decisionale (if-else), la selezione fra più alternative (switch), i cicli con condizione di terminazione posta in testa (while, for) ed in coda (do), ed infine l’uscita anticipata da un ciclo (break). Le funzioni possono restituire valori appartenenti ad un tipo base oppure strutture, union o puntatori. Qualsiasi funzione può essere richiamata ricorsivamente. Le variabili locali sono “automatiche”, cioè vengono ricreate ad ogni invocazione. Le definizioni di funzione non possono essere innestate, ma le variabili devono essere dichiarate secondo il metodo di strutturazione a blocchi. Le funzioni di un unico programma C possono trovarsi in file diversi che possono essere anche compilati separatamente. Le variabili possono essere dichiarate all’interno delle funzioni, al loro esterno ma visibili alle funzioni del singolo file, oppure accessibili da tutti i moduli del programma. Una fase che precede la compilazione vera e propria, detta preprocessing, attua una sostituzione delle macro all’interno del testo del programma, esegue l’inclusione di altri file sorgente e risolve le compilazioni condizionali. Il C è un linguaggio relativamente “a basso livello”. Questa caratteristica non è peggiorativa: significa soltanto che il C tratta gli oggetti (caratteri, numeri ed indirizzi) in modo molto simile a quello utilizzato dalla maggior parte dei calcolatori; questi oggetti, infatti, possono essere combinati e spostati con l’aiuto di operatori logici ed aritmetici implementati sulle macchine reali. Il C non fornisce operazioni per trattare direttamente oggetti compositi come le stringhe, gli insiemi, le liste od i vettori. Non ci sono operazioni che manipolano un intero vettore od una stringa, sebbene le strutture possano essere copiate come se fossero un unico oggetto. Il linguaggio non definisce alcuna funzionalità per l’allocazione di memoria, ad eccezione della definizione statica e della politica a stack utilizzata per le variabili locali alle funzioni; non esistono né uno heap né un meccanismo di garbage collection. Infine il C non prevede funzionalità esplicite di input / output; non esistono istruzioni di READ e WRITE, né metodi predefiniti di accesso ai file. Tutti questi meccanismi ad alto livello devono essere inclusi tramite esplicite chiamate di funzione. La maggior parte delle implementazioni realizzate in C ha incluso un ragionevole insieme standard di queste funzioni. Analogamente, il C prevede soltanto un controllo del flusso molto chiaro e lineare: controlli, cicli, raggruppa- menti e sottoprogrammi, ma non multiprogrammazione, operazioni parallele, sincronizzazioni o co-routine. Sebbene l’assenza di alcune di queste funzionalità possa sembrare una grave limitazione (“Vorreste dire che, per confrontare due stringhe di caratteri, è necessario chiamare esplicitamente una funzione?”), è necessario tenere presente che mantenere il linguaggio a dimensioni ridotte comporta notevoli vantaggi. Poiché il C è relativamente piccolo, può essere descritto in uno spazio limitato e appreso velocemente. Un programmatore, quindi, può ragionevolmente attendersi di conoscere, comprendere ed usare correttamente l’intero linguaggio. Per molti anni la definizione del C è stata quella presentata nel manuale di riferimento contenuto nella prima edizione de Linguaggio C. Nel 1983, l’Istituto Nazionale Americano per gli Standard (ANSI) ha costituito un comitato per la definizione aggiornata e completa del C. Il risultato di questo lavoro, lo standard ANSI, o “ANSI C”, è stato approvato nel 1989. Molte delle funzionalità di questo standard sono comunque già supportate dai compilatori più recenti. Lo standard si basa sul manuale di riferimento originale. Il linguaggio è variato soltanto in piccola parte; uno dei principali scopi dello standard, infatti, era di assicurare che i vecchi programmi continuassero a funzionare o che almeno, se ciò non fosse stato possibile, i compilatori fossero in grado di rilevare i nuovi comportamenti. Per la maggioranza dei programmatori, la novità maggiore riguarda l’introduzione di una nuova sintassi per la dichiarazione e la definizione di funzioni. Ora una dichiarazione di funzione deve includere la descrizione degli argomenti della funzione stessa; ovviamente, anche la sintassi della definizione è stata variata di conseguenza. Quest’informazione aggiuntiva consente ai compilatori di rilevare facilmente gli errori dovuti ad
no reviews yet
Please Login to review.