360 likes | 521 Views
Unità Didattica 1 Linguaggio C. Fondamenti. Struttura di un programma. La storia del Linguaggio C. UNIX (1969) - DEC PDP-7 Assembly Language
E N D
Unità Didattica 1Linguaggio C Fondamenti. Struttura di un programma.
La storia del Linguaggio C • UNIX (1969) - DEC PDP-7 Assembly Language • BCPL - un OS facilmente accessibile che fornisce potenti strumenti di sviluppo prodotti a partire da BCPL. Si tratta di un assemblatore noioso, lungo ed incline agli errori • Un nuovo linguaggio "B" come secondo tentativo (1970) • Un linguaggio "C" totalmente nuovo come successore di "B" (1971) • Dal 1973 UNIX OS, quasi totalmente scritto in C.
La storia del Linguaggio C • E’ stato utilizzato per sviluppare il sistema operativo UNIX, viene comunemente usato per scrivere sistemi operativi • Indipendente dall’hardware (portabile) • Standardizzazione: • inizialmente sono state definite molte piccole varianti del C, incompatibili tra loro; • ANSI (American National Standards Institute) si è occupato della sua standardizzazione, nel 1989, standard aggiornato nel 1999.
Caratteristiche del C • Linguaggio a medio/alto livello. Basso livello di controllodegli errori nella fase di compilazione. • Variabili tipizzate, con notevoli possibilità di conversione mediante il type casting, che permette di forzare una variabile a cambiare tipo; • Abbina ad un medio-alto livello di astrazione,un buon controllo delle operazioni a basso livello.
Fasi di traduzione ed esecuzione di unprogramma C • Traduzione: • Preprocessing: il preprocessore si occupa di includere altri file (es: librerie standard) e sostituisce simboli speciali che seguono particolari direttive (es: costanti simboliche); • Compilazione: traduzione del programma in codiceoggetto (linguaggio macchina (*.obj)); • Linking: risoluzione dei riferimenti a funzioni e variabilidefinite altrove (es. in librerie standard o definitedall’utente), producendo una immagine eseguibile (progr.exe); • Esecuzione: • Loading: caricamento in memoria il codice eseguibile; • Esecuzione delle istruzioni;
Primo programma in C #include <stdio.h> /*# = Preprocessore C precede le direttive che il compilatore valuta prima di iniziare la traduzione effettiva del programma (in questo caso l’inclusione della libreria delle funzioni standard di I/O (stdio.h)) */ main() /* Funzione principale, l’esecuzione di un programma C consiste nella esecuzione del main */ { printf(“Hello world\n”); /* Visualizza sullo standard output (monitor) la frase fra “ ” \n rappresenta un a capo */ }
Esecuzione • Ogni programma comincia la sua esecuzionecon la funzione main. • I commenti sono inseriti tra i caratteri /* e */ (oppure // per commentare un’intera riga) evengono ignorati in fase di compilazione. • In int main (void), la sintassi indica che il programma non ha argomenti di ingresso e che restituisce un valore intero (che indica la terminazione con successo).
Istruzioni e Librerie • Il set di istruzioni del C è molto limitato: leprimitive più comunemente utilizzate (es. I/O,matematiche) sono contenute nelle libreriestandard del C sotto forma di funzioni. • Se si utilizzano delle funzioni contenute in una certa libreria, questa deve essere inclusa mediante la direttiva #include del preprocessore. • Es: • la funzione dioutput printf() è contenuta della libreria standardstdio.h; • Per usare la funzione deve essere presente la direttiva diinclusione: • #include <stdio.h>
Preprocessore • # è il simbolo con cui iniziano i comandi del preprocessore. • Tali comandi nonsono terminati da “;” • Attraverso il preprocessore si esprimono direttive al compilatore; • Principali direttive: • Definizione delle costanti simboliche e dellemacro; • Compilazione condizionale del codice.
Preprocessore: #include • La direttiva #include: consente di includere inla copia di un file specificato. • Esistonodue forme: • #include <nome_file>viene utilizzata per includere file di intestazione (header file) della libreria standard, che sonomemorizzati in directory standard (dipendentidall’implementazione del compilatore); • #include “nome_file” cerca il file nella directory corrente, altrimenti in directory standard (perciò è utilizzata per includere header file definiti dal programmatore).
Preprocessore: #define • La direttiva #define è utilizzata per definirecostanti simboliche e macro. • Il formato è: • #define [identificatore][testo_di_sostituzione] • All’interno del file in cui è presentetutte le successive occorrenze dell’identificatoresaranno automaticamente sostituite dal testo_di_sostituzione, prima della compilazione.
Preprocessore: #define(per definizione di costanti simboliche) • #define PI 3.14159 sostituirà tutte le occorrenze della costantesimbolica PI con quella numerica 3.14159
Preprocessore: #define(per definizione di macro) • Le macropossono essere definite con o senza argomenti. • Una macro senza argomenti viene elaboratacome una costante simbolica. • In una macro con argomenti, essi sarannorimpiazzati all’interno del testo di sostituzionee solo in seguito sarà espansa la macro: ovvero, il testo di sostituzione rimpiazzeràla lista degli identificatori e degli argomenti all’interno del programma. • Esempio: • #define AREA_CERCHIO(x) ( PI * (x) * (x) ) ogni volta che nel programma appare AREA_CERCHIO(r) ilvalore di r sarà usato al posto di x, la costante PI sarà rimpiazzata dal suo valore (definito precedentemente) e la macro verrà espansa all’interno del programma.
Preprocessore: #define(per definizione di macro) • Esempio 1: • area = AREA_CERCHIO(4) sarà espanso in • area = ( 3.14159 * (4) * (4) ); • Esempio 2: • area = AREA_CERCHIO(c+2) sarà espanso in • area = ( 3.14159 * (c+2) * (c+2) ); • Vantaggi nell’uso delle macro: • risparmio nella definizione di una funzione; • miglioramento nella leggibilità del programma.
Preprocessore:Compilazione condizionale • Consente alprogrammatore di controllare la compilazione delcodice del programma. • Le direttive condizionalidel preprocessore vengono valutate come espressioni costanti intere. • Esempio: #define DEBUG #ifdef DEBUG printf(“Variabile x = %d\n”, x ); #endif l’istruzione printf viene compilata (ed eseguita) solo nel caso in cui la variabile DEBUG sia definita.
Variabili • In C ogni variabile è caratterizzata dai seguenti aspetti: • Tipo; • Classe di memoria. • Assegnare un tipo ad una variabile significa assegnarle il dominio dal quale assume i valori; • La classe di memoria determina la durata della vita (ciclo di vita) e l’ambito di visibilità (scope) delle variabili.
Tipi di dati • Tipi di base – char: carattere – int: intero – float: virgola mobile, singola precisione – double: virgola mobile, doppia precisione – void: indica che il dominio della variabile è l’insieme vuoto • Qualificatori: – unsigned: (es: unsigned int, unsigned char) – short: (es: short int) – long: (es: long int, long double)
Dichiarazione di Variabili • [tipo_var] var0, var1, …; • E' possibile inizializzare una variabile al momento della dichiarazione: • Esempi: int i, j, k=1; float x=2.6, y; char a;
Dichiarazione di Costanti • La definizione di identificatori per le costanti, oltreche con il comando di preprocessore #define, può avvenire usando il modificatore const: const tipo nome_costante = valore ; • Esempi: const double e = 2.71828182845905;
Funzioni • Generalizzazione del concetto di funzione algebrica: • legge che associa a valori delle variabili in ingresso valori della variabili in uscita o, più in generale, azioni. • Raggruppano operazioni che possono essere riutilizzate usando il nome della funzione e i suoi parametri (chiamata della funzione), senza preoccuparsi dell’aspetto implementativo; • I programmi in C combinano funzioni definite dal programmatore con funzioni di libreria standard; • Una funzione deve essere definita (definizione) e dichiarata (prototipo), prima della definizione, relativamente al nome e ai tipi dei parametri in ingresso e in uscita.
Parametri alle funzioni • Una funzione può avere dei parametri in ingresso e un parametro di uscita (tale fatto non rappresenta una limitazione perché si può restituire anche una struttura dati complessa); • Se non si vuol restituire alcun valore da una funzione èsufficiente dichiararla di tipo void ed omettere o meno il return; • E’ obbligatorio mettere le parentesi () (oppure (void)) dopo il nome della funzione anche se non ci sono parametri in ingresso. • void funz(void) oppure: void funz()
Parametri alle funzioni • In C i parametri alle funzioni sono sempre passati per valore; • Al momento della chiamata, le funzioni allocano (riservano) memoria per le variabili d’ingresso; • In ciascuna variabile viene copiato il valore che le viene passato al momento della chiamata.
Definizione e prototipo e chiamata di una funzione #include <stdio.h> [tipoUscita] nomeFunzione([tipo0],[tipo1]); //Prototipo void main() { [tipoUscita] a; [tipo0] x; [tipo1] y; … a = nomeFunzione(x, y); //Chiamata } [tipoUscita] nomeFunzione([tipo0] var0, [tipo1] var1) { //Definizione … }
Esempio di passaggio di parametri:Calcolo della potenza di un numero #include <stdio.h> int potenza(int, int); //Prototipo void main() { int x, y, z; x = 2; y = 3; z = potenza(x, y); //Chiamata } //Definizione int potenza(int base, int n) { int i, p = 1; for(i = 0; i < n; i++) p = p * base; return (p); } x y 3 2 Passaggio al momento della chiamata base n 3 2
Esempio di passaggio di parametri in funzioni ricorsive #include <stdio.h> long int fattoriale(int); //Prototipo void main() { long int fatt; int n; scanf(“%d”, &n); fatt = fattoriale(n); } long int fattoriale(int n) { if (n == 0) return 1; return (n * fattoriale(n-1)); }
Struttura di un programma C /* commenti: nome programma, descrizione, etc. */ #istruzioni per il preprocessore dichiarazione di tipi, variabili, costanti; prototipi delle funzioni; tipo_di_ritorno main (lista_argomenti) { dichiarazione variabili locali sequenza di istruzioni } tipo_di_ritorno funzione_1 (lista_argomenti) { dichiarazione variabili locali sequenza di istruzioni } tipo_di_ritorno funzione_n (lista_argomenti) { … }
Scrittura di un programma C su più moduli (file) • Quando si scrivono programmi di grosse dimensioni è consigliabilesuddividere i programmi in moduli separati. La funzione main() sarà contenuta in un solo file (es: “mioprogr.c”); • E’ buona norma concentrare inclusioni di librerie standard, dichiarazioni e prototipi necessari ad un modulo, in un unico file (header file) da includere in tale modulo (es: #include “mioprogr.h”); • Esiste un compromesso fra il desiderio che ogni modulo acceda solo alle informazioni di cui ha bisogno (N moduli => N header file) e la realtà pratica secondo la quale è difficile gestire molti header file; • Per programmi di dimensioni ridotte è meglio avere un unico header file contenente le informazioni da condividere fra due punti qualunque del programma scritto su più moduli e includere in essi l’unico header file creato;
Scrittura di un programma C su più moduli e un unico header file #include <mioprogr.h> void main() { … } #include <mioprogr.h> [tipo1] funz3([tipo0] var0) { … } [tipo5] funz2([tipo3] var1) { … } #include <mioprogr.h> [tipo0]funz0([tipo0] var0) { … } [tipo3]funz1([tipo0] var7) { … } mioprogr.c #include <stdio.h> #define … Variabili globali; Prototipi funzioni; mod1.c mod2.c Header file: file, da includere in ogni modulo,contenente inclusione di librerie,dichiarazioni e prototipi. mioprogr.h
Classi di Memorizzazione delle Variabili • Variabili locali (automatiche); • Variabili globali (esterne);
Variabili Locali (o automatiche) • Parola chiave auto o nessuna dichiarazione; • Sono interne ad un blocco individuato da … (es: interne ad una funzione); • Scope (ambito di visibilità): visibili (accessibili) solo all’interno del blocco di definizione; • Ciclo di vita: create al momento della dichiarazione, cessano di esistere quando si esce dal blocco; • Sono inizializzate con valori casuali.
Esempi di dichiarazione di variabili automatiche #include <stdio.h> void main(void) int i, j; … funz(); void funz() int i, j; //Sono variabili automatiche,ovvero //locali alla funzione. Fuori dalla //funz non sono più accessibili, cessano //di esistere (per esempio le due //variabili “i, j” definite nel “main” //sono del tutto scorrelate da queste).
Modifica del ciclo di vita di variabili locali • E’ possibile modificare il ciclo di vita di una variabile locale in modo che conservi il suo valore fra l’uscita e il successivo rientro nella funzione o nel blocco nel quale è stata dichiarata; • Tale modifica si ottiene anteponendo alle variabili locali la parola chiave static: void funz() static int i, j; //Sono variabili automatiche, ovvero //locali alla funzione. Fuori dalla //funz non sono più accessibili ma al //rientro nella funzione riacquistano //il valore che avevano al momento //dell’uscita dalla funzione stessa.
Variabili Globali (o esterne) • Sono dichiarate una sola volta esternamente a qualsiasi blocco; • Devono essere rese note alle funzioni o ad altri moduli tramite la parola chiave extern (eccetto il caso in cui la dichiarazione preceda la funzione o il blocco in uno stesso modulo (es: all’inizio di un modulo, come avviene nella pratica)). • Scope (ambito di visibilità): • Se rese note ad un blocco con l’uso di extern: ovunque, anche in moduli diversi; • Se rese note ad un blocco senza l’uso di extern: ovunque, nello stesso modulo, a partire dalla loro dichiarazione in avanti; • Ciclo di vita: Esistono e conservano il loro valore ovunque siano visibili all’interno del programma (es: uscita e successivo rientro da funzioni o blocchi);
Variabili globali in un unico modulo #include <stdio.h> int i, j; //variabili globali inizializzate a 0 void main(void) extern int i, j; //in questo caso la //dichiarazione viene //generalmente omessa int x; i = 2; j = 3; x = i + j;
Variabile globale condivisa in più moduli #include <stdio.h> extern int i; void funz(void); void funz(void) int j; j = i+1; … #include <stdio.h> int i; void main(void) funz(); mioprogr.c mod1.c i è globale per entrambi i moduli
Variabile globale condivisa in più moduli con uso di header file #include <stdio.h> int i; void funz(void); … mioprogr.h #include “mioprog.h” void funz() int j; j = i+1; … #include “mioprog.h” void main(void) funz(); i è globale perentrambi i moduli (mioprogr.c, mod1.c) mioprogr.c mod1.c