DICHIARAZIONI DI FUNZIONE
La dichiarazione di una funzione è
costituita dalla sola interfaccia,
senza corpo (sostituito da un ;)
<dichiarazione-di-funzione> ::=
<tipoValore> <nome>(<parametri>) ;
DICHIARAZIONI DI FUNZIONE
• Perché introdurre la
dichiarazione di
funzione?
• Non bastava la
definizione..???!?
DICHIARAZIONI DI FUNZIONE
Osservazione cruciale:
per usare un componente software
• non c’è bisogno di sapere
COME È FATTO
• basta sapere COME SI USA,
cioè - nel caso di una funzione come va invocata.
DICHIARAZIONI DI FUNZIONE
Dunque,
• non occorre conoscere tutta la
definizione
• basta conoscere la dichiarazione,
perché essa specifica proprio il
contratto di servizio!
DICHIARAZIONI DI FUNZIONE
• La definizione di una funzione
costituisce l’effettiva realizzazione
del componente
• La dichiarazione specifica il contratto di servizio fra cliente e servitore,
esprimendo le proprietà essenziali
della funzione.
DICHIARAZIONI DI FUNZIONE
• La definizione di una funzione
Dice come è fatto il
costituisce l’effettiva realizzazione
componente
del componente
• La dichiarazione specifica il contratto di servizio fra cliente e servitore,
esprimendo le proprietà essenziali
della funzione.
DICHIARAZIONI DI FUNZIONE
• La definizione di una funzione
costituisce l’effettiva realizzazione
del componente
Dice come si usa il
componente
• La dichiarazione specifica il contratto di servizio fra cliente
e
servitore,
Per usare una funzione
esprimendo le proprietà
non è essenziali
necessario
della funzione.
sapere come è fatta!
Anzi…
è controproducente!!
DICHIARAZIONI DI FUNZIONE
• La dichiarazione specifica:
– il nome della funzione
– numero e tipo dei parametri
(non necessariamente il nome)
– il tipo del risultato
interfaccia
DICHIARAZIONI DI FUNZIONE
• La dichiarazione specifica:
– il nome della funzione
– numero e tipo dei parametri
(non necessariamente il nome)
interfaccia
– il tipo del risultato
Il nome dei parametri non è
necessario: può esserci, ma
viene ignorato
DI FUNZIONE
Non deveDICHIARAZIONI
stupire:
esso avrebbe significato solo
•
La
dichiarazione
specifica:
nell’environment della funzione,
che qui
non c’è!
– il nome
della funzione
– numero e tipo dei parametri
(non necessariamente il nome)
interfaccia
– il tipo del risultato
Il nome dei parametri non è
necessario: può esserci, ma
viene ignorato
DEFINIZIONE vs. DICHIARAZIONE
• La definizione di una funzione
costituisce l’effettiva realizzazione
del componente
Non può essere
duplicata!
DEFINIZIONE vs. DICHIARAZIONE
• La definizione di una funzione
costituisce l’effettiva realizzazione
del componente
Non può essere
duplicata!
Una applicazione
deve contenere
una e una sola
definizione per ogni
funzione utilizzata
DEFINIZIONE vs. DICHIARAZIONE
• La definizione di una funzione
costituisce l’effettiva realizzazione
del componente
Non può essere
duplicata!
La compilazione
di una definizione
genera il codice
corrispondente
alla funzione.
Una applicazione
deve contenere
una e una sola
definizione per ogni
funzione utilizzata
DEFINIZIONE vs. DICHIARAZIONE
• La dichiarazione di una funzione
costituisce solo una specifica delle
proprietà del componente
Può benissimo
essere duplicata
senza danni
DEFINIZIONE vs. DICHIARAZIONE
• La dichiarazione di una funzione
costituisce solo una specifica delle
proprietà del componente
Può benissimo
essere duplicata
senza danni
Una applicazione
può contenerne
più di una
DEFINIZIONE vs. DICHIARAZIONE
• La dichiarazione di una funzione
costituisce solo una specifica delle
proprietà del componente
La compilazione
di una dichiarazione
non genera un
solo byte di codice
Può benissimo
essere duplicata
senza danni
Una applicazione
può contenerne
più di una
DEFINIZIONE vs. DICHIARAZIONE
• La definizione è molto più di una
dichiarazione
– definizione = dichiarazione + corpo
Per questo,
la definizione funge anche da
dichiarazione (non viceversa!)
FUNZIONI & FILE
• Un programma C è, in prima battuta,
una collezione di funzioni
– una delle quali è il main
• Il testo del programma deve essere
scritto in un file di testo
– un concetto del sistema operativo,
non del linguaggio C
Quali regole osservare ?
FUNZIONI & FILE
• Il main può essere scritto dove si
vuole nel file
– viene chiamato dal sistema operativo
• Una funzione, invece, deve rispettare
una regola fondamentale di visibilità
– prima che qualcuno possa chiamarla, la
funzione deve essere stata dichiarata
– altrimenti, si ha errore di compilazione.
File prova1.c
int fact(int);
ESEMPIO
main() {
int y = fact(3);
}
Dichiarazione: deve
precedere l’uso
Uso (chiamata)
int fact(int n) {
return (n<=1) : 1 : n*fact(n-1);
}
Definizione
FUNZIONI & FILE
• Il main può essere scritto dove si
Caso particolare: poiché la definizione
vuole
nel
file da dichiarazione, la
funge
anche
– viene
dal se
sistema
operativo
regolachiamato
è rispettata
la definizione
appare
prima invece,
della chiamata
• Una
funzione,
deve rispettare
una regola fondamentale di visibilità
– prima che qualcuno possa chiamarla, la
funzione deve essere stata dichiarata
– altrimenti, si ha errore di compilazione.
ESEMPIO
File prova2.c
int fact(int n) {
return (n<=1) : 1 : n*fact(n-1);
}
Definizione: funge anmain() {
che da dichiarazione
se precede l’uso
int y = fact(3);
}
Uso (chiamata)
FUNZIONI E VARIABILI LOCALI
• Il corpo di una funzione costituisce un
blocco del quale i parametri della funzione
sono considerati variabili locali
• In C e Java, come in molti altri linguaggi, è
permessa la definizione di nuove variabili
entro il corpo di una funzione
VARIABILI LESSICALI vs. LIBERE
• Le variabili la cui definizione compare
nell’ambito del blocco costituito dal corpo
della funzione (inclusi i parametri)
vengono chiamate variabili lessicali.
• Le variabili non definite entro il blocco
della funzione (e diverse dai parametri)
vengono chiamate variabili libere.
ESEMPIO
Variabili lessicali
float fahrToCelsius(float F){
float temp = 5.0 / 9;
return temp*(F - trentadue);
}
Variabile libera
FUNZIONI & SCOPE RULES
 Gli identificatori dichiarati dentro una
funzione (parametri formali inclusi)
sono visibili SOLO all'interno della
funzione
 Gli identificatori dichiarati nel blocco
in cui la definizione della funzione è
inserita sono visibili ANCHE dentro la
funzione (a meno che non siano ridefiniti)
ESEMPIO
int trentadue = 32;
float fahrToCelsius( float F ){
float temp = 5.0 / 9;
return temp * ( F - trentadue );
}
Variabile definita nel blocco in cui è inserita
la definizione della funzione
VARIABILI LIBERE &
COMPONENTI SOFTWARE
ATTENZIONE! Le variabili libere:
 introducono un accoppiamento fra cliente
e servitore
 condizionano l’utilizzo della funzione
all’esistenza di una definizione “esterna”
per la variabile libera
 limitano la riutilizzabilità della funzione
intesa come componente software.
ESEMPIO
int trentadue = 32;
float fahrToCelsius( float F ){
float temp = 5.0 / 9;
return temp * ( F - trentadue );
In C, una variabile definita
}
fuori da una funzione si dice
variabile globale
In effetti, il suo environment di definizione
ESEMPIO
non coincide con
quello di nessuna funzione
(neppure con quello del main)
int trentadue = 32;
float fahrToCelsius( float F ){
float temp = 5.0 / 9;
return temp * ( F - trentadue );
In C, una variabile definita
}
fuori da una funzione si dice
variabile globale
VARIABILI GLOBALI
• Una variabile globale è definita
fuori da qualunque funzione
(“a livello esterno”)
• tempo di vita = intero programma
• scope = il file in cui è dichiarata
(dal punto in cui è scritta in avanti)
ESEMPIO
int trentadue = 32;
float fahrToCelsius( float F ){
float temp = 5.0 / 9;
return temp * ( F - trentadue );
}
Definizione (e inizializzazione)
di una variabile globale
VARIABILI: DICHIARAZIONI E DEFINIZIONI
• Anche per le variabile globali si
distingue fra dichiarazione e
definizione
– al solito, la dichiarazione esprime
proprietà associate al simbolo,
ma non genera un solo byte di codice
– la definizione invece implica anche
allocazione di memoria
VARIABILI: DICHIARAZIONI E DEFINIZIONI
• Regola fondamentale di visibilità:
– prima dell’uso, una variabile globale
deve almeno essere stata dichiarata
– Caso particolare: la definizione può
fungere anche da dichiarazione
ESEMPIO
File prova3.c
Definizione (e iniint trentadue = 32;
zializzazione) della
float fahrToCelsius(float);
variabile globale
main() {
float c = fahrToCelsius(86);
}
float fahrToCelsius(float f) {
return 5.0/9 * (f-trentadue);
}
Uso della var.glob.
VARIABILI: DICHIARAZIONI E DEFINIZIONI
• Come distinguere la dichiarazione
da una definizione?
– non c’è l’analogo del corpo della funzione..
• Si usa la parola chiave extern
– int trentadue = 10;
è una definizione (con inizializzazione)
– extern int trentadue;
è una dichiarazione
ESEMPIO
File prova4.c
extern int trentadue;
Dichiarazione
variabile globale
float fahrToCelsius(float f) {
return 5.0/9 * (f-trentadue);
}
Uso della var.glob.
main() {
float c = fahrToCelsius(86);
}
Definizione della
int trentadue = 32;
variabile globale
VARIABILI: DICHIARAZIONI E DEFINIZIONI
• Come sempre, una applicazione può
contenere
– più dichiarazioni per lo stesso simbolo
– ma una e una sola definizione di tale
simbolo.
• NB: la dichiarazione non può contenere anche una inizializzazione
– è solo un avviso, la variabile non è lì!
FUNZIONI come COMPONENTI SW
• Una funzione è un componente software
• che ha un suo environment di definizione
• e può essere invocato per nome da altre
funzioni (in particolare, dal main)
Dove scrivere le funzioni?
Quali regole pratiche?
Quale organizzazione?
COSTRUZIONE DI UN’APPLICAZIONE
Per costruire un’applicazione occorre
• compilare il file (o i file se più d’uno)
che contengono il testo del programma
(file sorgente)
Il risultato sono uno o più file oggetto.
• collegare i file oggetto l’uno con l’altro
e con le librerie di sistema.
COMPILAZIONE DI UN’APPLICAZIONE
1) Compilare il file (o i file se più d’uno)
che contengono il testo del programma
– File sorgente:
estensione .c
– File oggetto:
estensione .o o .obj
f1.c
f1.obj
compilatore
COMPILAZIONE DI UN’APPLICAZIONE
1) Compilare il file (o i file se più d’uno)
Una
che però
che contengono
il versione
testo deltradotta
programma
non è autonoma (e, quindi,
– File sorgente:
estensione .c
non è direttamente eseguibile).
– File oggetto:
estensione .o o .obj
f1.c
f1.obj
compilatore
COLLEGAMENTO DI UN’APPLICAZIONE
2) Collegare il file (o i file) oggetto fra loro
e con le librerie di sistema
– File oggetto:
estensione .o o .obj
– File eseguibile:
estensione .exe o nessuna
f1.obj
linker
prog.exe
LIBRERIE DI
SISTEMA
Programma eseguibile
COSTRUZIONE DI UN’APPLICAZIONE
Perché tutto questo?
• il nostro programma non è destinato a
funzionare sulla macchina "nuda", ma sulla
macchina rivestita dal sistema operativo
• quindi il nostro programma, per funzionare,
deve necessariamente interfacciarsi col
sistema operativo stesso.
COSTRUZIONE DI UN’APPLICAZIONE
Non solo:
• alcune istruzioni “complesse” del linguaggio
potrebbero essere realizzate in realtà da
"mini-programmi" forniti insieme al compilatore, che li "ingloba" quando occorre.
LIBRERIE DI SISTEMA:
insieme di componenti software che consentono di interfacciarsi col sistema operativo,
usare le risorse da esso gestite, e realizzare
alcune "istruzioni complesse" del linguaggio
COSTRUZIONE DI UN’APPLICAZIONE
Last but not least...
• una applicazione complessa non può
essere sviluppata in un unico file:
sarebbe ingestibile!
• deve necessariamente essere strutturata
su più file sorgenti, che devono poter
essere compilati separatamente
• per essere poi fusi insieme alla fine.
COSTRUZIONE “MANUALE”
In passato, la costruzione si faceva “a
mano”, attivando compilatore e linker dalla
linea di comando del sistema operativo
(DOS, Unix, ...)
C:\PROVA> gcc -c f1.c
(genera f1.obj)
C:\PROVA> ld -o prog.exe f1.obj –lc
(genera prog.exe)
Eseguibile
da produrre
File oggetto
Libreria C
AMBIENTI INTEGRATI
Oggi, gli ambienti di lavoro integrati automatizzano la procedura:
 compilano i file sorgente (se e quando
necessario)
 invocano il linker per costruire l’eseguibile
ma per farlo devono sapere:
 quali file sorgente costituiscono
l’applicazione
 il nome dell’eseguibile da produrre.
PROGETTI
È da queste esigenze che nasce il concetto
di PROGETTO
• un contenitore concettuale (e fisico)
• che elenca i file sorgente in cui
l’applicazione è strutturata
• ed eventualmente altre informazioni utili.
Oggi, tutti gli ambienti di sviluppo integrati, per
qualunque linguaggio, forniscono questo
concetto e lo supportano con idonei strumenti.
PROGETTI IN DJGPP/RHide
Si sceglie la voce di menù
Project  Open Project,
e, nella finestra che appare, si
sceglie un nome per il nuovo
progetto (che sarà anche il nome
dell’eseguibile)
PROGETTI IN DJGPP/RHide
Si va poi nella Project Window che appare, e si
preme sulla tastiera il tasto INS (o si sceglie da menù
l’opzione Project  add item)
PROGETTI IN DJGPP/RHide
Dalla finestra Add item che appare si selezionano
i file sorgente che si vogliono inserire nel progetto.
PROGETTI IN DJGPP/RHide
Facendo doppio clic su un nome
di file (ad esempio, f1.c) si apre
l’editor per modificarlo.
PROGETTI IN DJGPP/RHide
A questo punto:
 per compilare, Compile  Compile (ALT+F9)
(ricompila solo i file modificati dall’ultima compilazione)
 per collegare, Compile  Link
PROGETTI IN DJGPP/RHide
Oppure le due fasi insieme:
Compile  Make (F9)
A questo punto:
 per compilare, Compile  Compile (ALT+F9)
(ricompila solo i file modificati dall’ultima compilazione)
 per collegare, Compile  Link
PROGETTI IN TURBO C
Dal sceglie il menù
Project  New Project,
(oppure l’icona in alto)...
PROGETTI IN TURBO C
La finestra che appare richiede
varie informazioni.
1) percorso e nome del progetto
(per default coincide con il
Target Name, cioè col nome
dell’eseguibile da produrre)
PROGETTI IN TURBO C
2) il Target Type, cioè il tipo
di applicazione da generare:
essenziale scegliere EasyWin
(non Application)
Turbo C è un ambiente multi-target, cioè
può produrre sia applicazioni per Windows
(che vanno strutturate in modo particolare),
sia applicazioni standard da eseguire in una
finestra di Windows emulando una console.
3) premendo
il tasto
PROGETTI IN TURBO
C
Advanced:
un nodo iniziale .c
nessuna risorsa
(né .rc, né .def)
PROGETTI IN TURBO C
Si va poi nella finestra Project che appare, e si
preme sulla tastiera il tasto INS (o si fa clic nella finestra
con il tasto destro e si sceglie la voce Add Node)
PROGETTI IN TURBO C
Dalla finestra Add to Project List
si selezionano i file da inserire nel progetto.
PROGETTI IN TURBO C
Facendo doppio clic su un nome
di file (ad esempio, aaa.c) si apre
l’editor per modificarlo.
PROGETTI IN TURBO C
A questo punto:
 per compilare, Project  Compile (ALT+F9)
(ricompila solo i file modificati dall’ultima compilazione)
 per collegare, Project  Make all (F9)
(fa le due fasi insieme; non si può solo collegare)
ESEGUIRE IL PROGRAMMA
Una volta scritto, compilato e collegato il
programma (ossia, costruito l’eseguibile)
Come si esegue il programma?
Come “spiare” quello che fa?
Occorre uno strumento che consenta di
• eseguire il programma passo per passo
• vedendo le variabili e la loro evoluzione
• e seguendo le funzioni via via chiamate.
ESEGUIRE IL PROGRAMMA
Una volta scritto, compilato e collegato il
programma (ossia, costruito l’eseguibile)
Come si esegue il programma?
Come “spiare” quello che fa?
Occorre uno strumento che
consenta di
IL DEBUGGER
• eseguire il programma passo per passo
• vedendo le variabili e la loro evoluzione
• e seguendo le funzioni via via chiamate.
ESEGUIRE IL PROGRAMMA
Sia Rhide sia TURBO C incorporano un
debugger con cui eseguire il programma
• riga per riga
– entrando anche dentro alle funzioni chiamate
(Run  trace into; F7) (Debug  trace into; F7)
– oppure considerando le chiamate di funzione
come una singola operazione
(Run  step over; F8) (Debug  step over; F8)
• oppure fino alla riga desiderata
(Run  Go to cursor; F4) (F4)
ESEGUIRE IL PROGRAMMA
… e con cui inoltre è possibile:
• controllare istante per istante quanto vale
una variabile
– Debug  Watch an expression (CTRL+F7)
– Debug  Add watch (CTRL+F5)
• vedere istante per istante le funzioni attive
(record di attivazione nello stack)
– Debug  Call stack (CTRL+F3)
– View  Call stack
UN ESEMPIO COMPLETO: IL FATTORIALE
Project: c:\temp\fatt
Target Name:
fatt
Target Type:
EasyWin
ESEMPIO: IL FATTORIALE
Source node: fatt.c
ESEMPIO: IL FATTORIALE
Si scrive il programma,
lo si salva, e...
ESEMPIO: IL FATTORIALE
… lo si costruisce (F9).
Se non ci sono errori...
ESEMPIO: IL FATTORIALE
… si può passare a eseguirlo con il debugger.
Premendo F7 ci si posiziona
all’inizio del main.
ESEMPIO: IL FATTORIALE
Premendo ancora F7 ci si
posiziona sulla prima istruzione, pronti per eseguirla.
ESEMPIO: IL FATTORIALE
Volendo, si può mettere sotto
osservazione la variabile y,
sfruttando l’Add watch.
Inoltre, si possono vedere i
record di attivazione con il
View Call Stack (ora, ovviamente, c’è solo il main)
ESEMPIO: IL FATTORIALE
Via via che l’esecuzione prosegue, il Call Stack mostra
la successione dei record di
attivazione che si accumulano.
Si noti che la variabile y
risulta ora indefinita: siamo
usciti dallo scope del main!
Però, possiamo aggiungere
ai watch la variabile v, che
esiste nello scope di factIter.
ESEMPIO: IL FATTORIALE
Nel momento di massima espansione (che coincide col momento
in cui si ha il risultato), il Call
Stack mostra ben 5 record attivi.
Si noti che v, come previsto,
vale attualmente 6 (che costituisce il risultato)
ESEMPIO: IL FATTORIALE
Appena prima che il main termini,
y vale finalmente 6.
La computazione è completata.
ESEMPIO: IL FATTORIALE
Quando il main è terminato,
nessuna variabile esiste più
Tutto è scomparso.
Scarica

12-Progetti