Il 0% ha trovato utile questo documento (0 voti)
2 visualizzazioni18 pagine

L03 - Code Structure

Il documento tratta della programmazione modulare, evidenziando l'importanza di moduli indipendenti che nascondono dettagli implementativi e facilitano la cooperazione in team. Viene discusso il concetto di information hiding, accoppiamento e coesione, sottolineando la necessità di minimizzare l'accoppiamento e massimizzare la coesione per migliorare la manutenibilità e la riusabilità del codice. Infine, vengono descritti i moduli in C, il loro scope, linkage, prototipi e il processo di compilazione e linking.

Caricato da

ChargedCreeperPB
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
2 visualizzazioni18 pagine

L03 - Code Structure

Il documento tratta della programmazione modulare, evidenziando l'importanza di moduli indipendenti che nascondono dettagli implementativi e facilitano la cooperazione in team. Viene discusso il concetto di information hiding, accoppiamento e coesione, sottolineando la necessità di minimizzare l'accoppiamento e massimizzare la coesione per migliorare la manutenibilità e la riusabilità del codice. Infine, vengono descritti i moduli in C, il loro scope, linkage, prototipi e il processo di compilazione e linking.

Caricato da

ChargedCreeperPB
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd

Struttura di un programma

File e moduli
Linkage, scope e prototipi
Compilazione e linking
Programmazione modulare
 Tecnica di programmazione che ha lo scopo di aumentare l’indipendenza tra le
sue parti costituenti, dette componenti o moduli
 Un modulo
– Raccoglie un insieme di funzionalità omogenee
– Nasconde i dettagli implementativi
– Costituisce una unità il più possibile completa e indipendente
 Un modulo software è costituito da
– Una interfaccia
• Descrive gli elementi che sono forniti e richiesti dal modulo
• E visibile e accessibile ad altri moduli
– Una implementazione
• Realizza quanto esposto dall’interfaccia
• Può essere completamente ignota a chi utilizza il modulo

(c) 2012 - Carlo Brandolese


Programmazione modulare
 Costituisce la soluzione alternativa all’approccio monolitico
– Un unico complesso software risolve l’intero problema
– E’ indispensabile individuare un buon compromesso tra
• Semplicità dei signoli moduli
• Complessità delle relazioni tra di essi
 Realizza il principio “divide and conquer”
– Cooperazione di diversi moduli indipendenti che risolvono sottoproblemi più semplici
 Consente di organizzare il lavoro di sviluppo in team
– Richiede una attenta fase iniziale di definizione dell’architettura complessiva del sistema
 Affinchè l’approccio modulare porti ad un reale beneficio è necessario che i
moduli abbiano alcune proprietà
– Elevato livello di information hiding
• Nascondere all’utente del modulo i dettagli implementativi
– Basso accoppiamento
• Dipendenza da altri moduli
– Elevata coesione
• Omogeneità delle funzioni offerte da un modulo

(c) 2012 - Carlo Brandolese


Information hiding
 Si definisce information hiding il principio secondo cui
– Si nascondono le decisioni implementative di un modulo agli utenti del modulo stesso

 In particolare si vuole nascondere


– Dati
• Le strutture dati interne ad un modulo
• La rappresentazione dei dati
– Algoritmi
• Il modo specifico in cui un dato comportamento viene realizzato

 Si vuole invece esporre


– Una interfaccia di accesso ai dati
– Una interfaccia di accesso alle funzionalità

 E' bene cercare di massimizzare l'information hiding

(c) 2012 - Carlo Brandolese


Accoppiamento
 L'accoppiamento misura livello di dipendenza reciproca tra due moduli

 Dati due moduli A e B si ha accoppiamento se


– A ha un attributo che si riferisce a B
– A chiama una funzione di B
– A definisce una funzione che si riferisce a tipi definiti in B
– A definisce una struttura che contiene un tipo definito in B

 L’accoppiamento
– Tende a migliorare le prestazioni
– Tende a diminuire la modularità e la riusabilità del codice

 E' bene cercare di minimizzare l'accoppiamento

(c) 2012 - Carlo Brandolese


Accoppiamento - Tipologie
 Contenuto (alto)
– Un modulo dipende dal modo in cui un’altro è strutturato internamente
• La posizione in memoria di un dato, da un tipo di un dato o dalle tempistiche di elaborazione
 Dati comuni
– Due moduli utilizzano dati globali comuni
 Esterno
– Due moduli condividono un formato dei dati definito esternamente
• Una interfaccia comune o un protocollo
 Controllo
– Un modulo passa ad un altro informazioni che ne modificano il flusso di esecuzione
• Per esempio un flag
 Strutture dati
– Due moduli usano campi diversi di una stessa struttura dati
 Parametri
– Un modulo passa parametri ad un altro modulo mediante chiamate di funzione
 Messaggi (basso)
– Un modulo utilizza una funzione di un altro modulo priva di argomenti

(c) 2012 - Carlo Brandolese


Coesione
 La coesione misura quanto sono correlate le diverse parti di un modulo

 Una bassa coesione


– Rende difficile comprendere le funzioni svolte da un modulo
– Rende difficile la manutenzione del modulo poiché un cambiamento si riflette su ambiti
diversi del programma
– Rende difficile o inefficiente il riuso del codice

 Una elevata coesione


– Può rendere meno efficiente il codice
– Può causare una eccessiva suddivisione in moduli

 È bene massimizzare la coesione dei moduli

(c) 2012 - Carlo Brandolese


Coesione - Tipologie
 Casuale (peggiore)
– Un modulo raccoglie funzioni e dati scelti arbitrariamente
 Logica
– Un modulo raccoglie funzioni correlate logicamente ma prive vi relazioni forti P
• Per esempio tutte le funzioni di I/O
 Temporale
– Un modulo raccoglie le funzioni che vengono usate in momenti vicini nel tempo
• Per esempio funzioni che gestiscono eccezioni su un file, creano un log e notificano un errore
 Procedurale
– Un modulo raccoglie funzioni usate sempre in sequenza
• Per esempio funzioni che verificano i permessi su un file, lo aprono, lo modificano e lo chiudono
 Comunicazione
– Un modulo raggruppa le funzioni che operano su uno stesso dato
 Sequenziale
– Un modulo raggruppa funzioni per cui l’output di una serve come input di un’altra
 Funzionale (migliore)
– Un modulo raggruppa tutte le funzioni che svolgono una ben precisa funzione
• Per esempio la costruzione e la visita di un albero
(c) 2012 - Carlo Brandolese
Moduli in C
 Un modulo in C è sempre costituito da
– Un file header (.h) che dichiara l'interfaccia
– Uno o più file sorgenti (.c) che definiscono dati e funzioni

 Esempio: Contatore
– Specifica
• Il modulo deve implementare un contatore unico e condiviso da tutti gli utenti

– Interfaccia
• Le funzioni richieste sono incremento, lettura e reset
• Il contatore deve poter essere configurato a compile-time per avere la funzione opzionale di
decremento

– Implementazione
• Il modulo deve disporre di una variabile interna che mantiene il valore corrente
• Il modulo deve implementare le funzioni dell'interfaccia

(c) 2012 - Carlo Brandolese


Moduli in C
counter.h  Compilazione condizionale
#ifndef COUNTER_H
#define COUNTER_H
– COUNTER_H
• Definita la prima volta che il file è incluso
/* Mandatory functions ***********************/
• Previene l'inclusione multipla
void cnt_reset( void ); COUNTER_H Undefined
f1.c
void cnt_inc( void ); Header included
int cnt_get( void ); COUNTER_H defined
counter.h

/* Optional function *************************/


x.h
#ifdef CNT_HAS_DECREMENT
void cnt_dec( void ); y.h
#endif
Header not included
counter.h
#endif

z.h

– CNT_HAS_DECREMENT
• Deve essere definita dal programmatore
• Se definita, causa la definzione della
funzione di decremento

(c) 2012 - Carlo Brandolese


Moduli in C
counter.c  Il valore del contatore non deve
#include "counter.h" essere visibile direttamente dal di
/* Hidden data *******************************/ fuori del modulo
static int cnt = 0;
– Si rende il simbolo cnt statico
• Si dice che il simbolo ha "internal linkage"
/* Implementation ****************************/
– Si forniscono funzioni di accesso
void cnt_reset( void ) { • In lettura
cnt = 0;
}
• In scrittura
void cnt_inc( void ) {  Anche l'implementazione della
cnt++;
} funzione di decremento deve essere
sotto compilazione condizionale
int cnt_get( void ) {
return cnt;
}

#ifdef CNT_HAS_DECREMENT
void cnt_dec( void ) {
cnt--;
}
#endif

(c) 2012 - Carlo Brandolese


Scope e linkage
 Un simbolo globale può essere
– Una variabile o una costante
– Una funzione
 Per comprendere come sono trattati i simboli sono necessari tre concetti
– Scope:
• La parte di codice in cui un simbolo è visibile, cioè noto al compilatore
– Linkage:
• L'area in cui il simbolo è visibile al linker
– Translation unit:
• La parte di codice che il compilatore tratta in una sola volta
 I simboli globali
– Hanno scope "globale" o "file scope", sono visibili nella translation unit corrente
– Hanno "external linkage", sono potenzialmente visibili in altre translation unit
 Il modificatore static
– Cambia il linkage da external a internal
– Non modifica lo scope

(c) 2012 - Carlo Brandolese


Scope e linkage
 Variabile e funzione a file scope con linkage esterno
a.c
int var;
int other;
int fun( float ) {...}

– La funzione fun() può essere usata direttamente in altre translation unit


• Tuttavia non ne sarà noto il prototipo (vedi oltre)
– Le variabili var e other possono essere usata in altre translation unit
• Se specificato esplicitamente mediante la dichiarazione extern
 In un'altra translation unit, dunque
b.c
extern int var;

void bar() {
int n = var + 1;
int m = fun( 1.5 );
int k = other – 1; /* Linker error: other is unknown to the linker */
...
}

(c) 2012 - Carlo Brandolese


Scope e linkage
 Variabile e funzione a file scope con linkage interno
a.c
static int var;
static int other;
static int fun( float ) {...}

– Né le variabili né la funzione possono essere usate in altre translation unit


 In un'altra translation unit, dunque
b.c
extern int var; /* Linker error: conflicts with static declaration */
extern int fun(float); /* Linker error: conflicts with static declaration */

void bar() {
int n = var + 1;
int m = fun( 1.5 );
int k = other – 1; /* Linker error: other is unknown to the linker */
...
}

– Il modificatore extern usato in un'altra translation unit non ha alcun effetto


– Se usato per cercare di accedere a var o a fun() produce un errore in fase di linking

(c) 2012 - Carlo Brandolese


Prototipi
 Il "prototipo" o "signature" di una funzione ne dichiara
– Il nome
– Il tipo di ritorno
– Il numero de il tipo di ogni argomento
 Per default, il compilatore assume che una funzione
– Abbia sempre tipo di ritorno int
– Abbia un numero qualsiasi di argomenti int
 Se una funzione è dichiarata in una translation unit ed usata in un'altra
– E' necessario indicare il suo prototipo nella translation unit in cui è usata
 Il prototipo deve essere completo ed esplicito
– Se una funzione non ritorna alcun valore deve essere dichiarata come void
– Se una funzione non accetta alcun argomento deve avere una lista di argomenti void
/* INCOMPLETE PROTOTYPES */
f1(); /* Return type is int, accepts an unspecified number of int arguments */
char f2(); /* Return type is char, accepts an unspecified number of int arguments */
void f3(); /* No return type, accepts an unspecified number of int arguments */
int f4(void); /* Return type is int, accepts no arguments */
/* COMPLETE PROTOTYPE */
int f5(int); /* Return type is int, accepts a single int argument */

(c) 2012 - Carlo Brandolese


Compilazione e linking
 Il processo di compilazione è complesso e articolato
– Spesso viene nascosto da un unica interfaccia (grafica o command-line)
– Si compone di diversi passi
 Preprocessore (cpp)
– Analizza le macro e le direttive di preprocessore
– Ignora il linguaggio C
– Produce un nuovo file sorgente
 Compilatore (cc1)
– Traduce il codice sorgente in codice assembly simbolico
 Assembler (as)
– Traduce il codice assembly simbolico in codice macchina
– Il risultato è un file oggetto
 Linker (ld, ar, ranlib)
– Combina più file oggetti in
• Un eseguibile (ld)
• Una libreria (ar, ranlib)

(c) 2012 - Carlo Brandolese


Compilazione e linking

User Application User Library User Library System Libraries

f1.c f2.c fN.c l1.c lK.c m1.c mP.c

cpp cpp cpp cpp cpp cpp cpp


cc1 cc1 cc1 cc1 cc1 cc1 cc1
as as as as as as as

f1.o f2.o fN.o l1.o lK.o m1.o mP.o

ar ar
ranlib ranlib

l.a m.a s1.a sL.a

ld

[Link]

(c) 2012 - Carlo Brandolese


Compilazione e linking

f1.c f2.c fN.c l1.c lK.c m1.c mP.c Sources

cpp cpp cpp cpp cpp cpp cpp


cc1 cc1 cc1 cc1 cc1 cc1 cc1
as as as as as as as

f1.o f2.o fN.o l1.o lK.o m1.o mP.o Objects

ar ar
ranlib ranlib

Libraries l.a m.a s1.a sL.a

ld

Executable [Link]

(c) 2012 - Carlo Brandolese

Potrebbero piacerti anche