Appunti per Scuola e Università
humanisticheUmanistiche
Appunti e tesine di tutte le materie per gli studenti delle scuole medie riguardanti le materie umanistiche: dall'italiano alla storia riguardanti le materie umanistiche: dall'italiano alla storia 
sceintificheScientifiche
Appunti, analisi, compresione per le scuole medie suddivisi per materie scientifiche, per ognuna troverai appunti, dispense, esercitazioni, tesi e riassunti in download.
tecnicheTecniche
Gli appunti, le tesine e riassunti di tecnica amministrativa, ingegneria tecnico, costruzione. Tutti gli appunti di AppuntiMania.com gratis!
Appunti
informatica
CComputerDatabaseInternetJava
Linux unixReti


AppuntiMania.com » Informatica » Appunti di c » Scrivere funzioni di libreria

Scrivere funzioni di libreria




Visite: 1517Gradito:apreciate 5-stela [ Medio appunti ]
Leggi anche appunti:

Scrivere funzioni di libreria


Scrivere funzioni di libreria La scrittura di un programma C implica sempre

Il flusso elaborativo


Il flusso elaborativo Qualsiasi programma può venire codificato in un linguaggio

C come cesare


C come Cesare Il Cesare in questione è proprio Caio Giulio Cesare, il noto imperatore romano
immagine di categoria

Scarica gratis Scrivere funzioni di libreria

Scrivere funzioni di libreria

La scrittura di un programma C implica sempre la necessità di scrivere funzioni, in quanto almeno main() deve essere definita. Spesso, però, le funzioni che fanno parte di uno specifico programma sono scritte avendo quali linee guida la struttura e gli obiettivi di quello. Leggermente diverso è il comportamento da tenere quando si scrivano funzioni destinate a far parte di una libreria e, come tali, utilizzabili almeno in teoria da qualsiasi programma: in questo caso è opportuno osservare alcune regole, parte delle quali derivano dal buon senso e dalla necessità di scrivere codice qualitativamente valido; parte, invece, dettate dalle esigenze tecniche del linguaggio e dei compilatori.

Accorgimenti generali

Nello scrivere funzioni di libreria va innanzitutto ricordato che il codice scritto può essere utilizzato nelle situazioni più disparate: è pertanto indispensabile evitare, per quanto possibile, qualsiasi assunzione circa le condizioni operative a runtime.

Supponiamo, ad esempio, di scrivere una funzione in grado di copiare in un buffer il contenuto della memoria video: se il codice deve far parte di un programma, magari preparato per una specifica macchina, è possibile che le modalità operative (tipo di monitor, pagina video attiva) siano note al momento della compilazione e non pongano dunque problemi di sorta. Ma se la funzione deve essere inserita in una libreria, non può ipotizzare nulla circa tali condizioni: è opportuno, allora, che esse siano richieste quali parametri. In alternativa la funzione stessa può incorporare alcune routine atte a conoscere tutti i parametri operativi necessari mediante le opportune chiamate al BIOS. Oppure, ancora, possono essere predisposte una o più funzioni 'complementari', da chiamare prima di quella in questione, che memorizzino i dati necessari in variabili globali.

L'indipendenza del codice dalle condizioni operative del programma è anche detta parametricità, e rappresenta un requisito essenziale delle funzioni di libreria.

Un'altra importante osservazione riguarda la coerenza delle regole di interfacciamento funzioni/programma. Accade spesso di scrivere gruppi di funzioni le quali, nel loro insieme, permettono di gestire in modo più o meno completo determinate situazioni o caratteristiche del sistema in cui opera il programma che le utilizza. E' bene che le funzioni inserite in una libreria, ed in particolare quelle che implementano funzionalità tra loro correlate, siano simili quanto a parametri, valori restituiti e modalità di gestione degli errori. In altre parole, esse dovrebbero, per quanto possibile, somigliarsi reciprocamente. Con riferimento ad un gruppo di funzioni che utilizzino servizi DOS per realizzare particolari funzionalità, si può pensare ad una modalità standard di gestione degli errori, nella quale il valore restituito è sempre il codice di stato a sua volta restituito dal DOS. In alternativa ci si può uniformare alla modalità implementata da gran parte delle funzioni della libreria standard, che prevedono la restituzione del valore  in caso di errore e la memorizzazione del codice di errore nella variabile globale errno: a pag.  sono forniti la descrizione di come tale algoritmo sia realizzato nella libreria C ed un esempio di utilizzo della funzione (non documentata)___IOerror()

Ancora, i nomi di variabili e funzioni dovrebbero essere il più possibile autoesplicativi: dalla loro lettura dovrebbe cioè risultare evidente il significato della variabile o il compito della funzione. Al proposito sono state sviluppate specifiche formali che descrivono un possibile metodo per uniformare i nomi C basato, tra l'altro, sulle modalità di allocazione delle variabili e su un insieme di suffissi standard per le funzioni. Se non si scrive codice a livello professionale, tali formalismi possono forse risultare eccessivi; è bene comunque ricordarsi che le funzioni di libreria sono spesso utilizzate da terzi, i quali è bene possano concentrarsi sul programma che stanno implementando piuttosto che essere costretti a sforzarsi di decifrare significati e modalità di utilizzo di una interfaccia software criptica, disordinata e disomogenea.

Analoghe considerazioni valgono per la documentazione delle funzioni. E' indispensabile che le librerie siano accompagnate da una chiara e dettagliata descrizione, per ciascuna funzione, del tipo e del significato di tutti i parametri richiesti e del valore eventualmente restituito. Del pari, è opportuno fornire esaustiva documentazione delle strutture ed unioni definite, delle variabili globali e delle costanti manifeste.

Esigenze tecniche

Alcune regole derivano invece dalle caratteristiche proprie del linguaggio C e dei compilatori. Si è detto (pag.  e seguenti) che, per verificare la correttezza sintattica della chiamata a funzione e gestirla nel modo opportuno, il compilatore deve conoscere le regole di interfacciamento tra la stessa funzione e quella chiamante (cioè la coerenza tra i parametri formali e quelli attuali). Dal momento che una funzione di libreria non è mai definita nel sorgente del programma che ne fa uso, è necessario fornirne il prototipo. Allo scopo si rivelano particolarmente adatti gli header file .H): è bene, pertanto, che una libreria di funzioni sia sempre accompagnata da uno o più file .H contenenti tutti i prototipi delle funzioni, la dichiarazione (come variabili external, pag.  ) di tutte le variabili globali, i template delle strutture ed unioni, nonché le costanti manifeste eventualmente definite per comodità del programmatore.

Si ricordi, poi, che una libreria di funzioni non è che un file contenente uno o più object file .OBJ), generati dalla compilazione dei rispettivi sorgenti. Detti moduli oggetto possono derivare da sorgenti scritti in linguaggi diversi dal C: è frequente, soprattutto per l'implementazione di rouine dei basso livello, il ricorso al linguaggio Assembler. E' evidente che negli include file devono essere dati anche i prototipi delle funzioni facenti parti di moduli assembler. Inoltre, dal momento che, per default, il compilatore genera un underscore (il carattere ' ') in testa ai nomi delle funzioni C, mentre ciò non viene fatto dall'assemblatore, i nomi di tutte le funzioni definite in moduli assembler devono inziare con un underscore, che viene ignorato nelle chiamate nel sorgente C. Se, ad esempio, la libreria contiene il modulo oggetto relativo alla funzione assembler definita come segue:


_machineType proc near

.

_machineType endp


il prototipo fornito nello header file è:

int machineType(void);                        // senza undescore iniziale!!

e le chiamate nel sorgente C saranno analoghe alla seguente:

.

int cpu;

.

cpu = machineType(); // niente underscore neppure qui!

.

Va ancora sottolineato che, essendo il C un linguaggio case‑sensitive , anche la compilazione dei sorgenti assembler mediante l'assemblatore deve essere effettuata in modo che le maiuscole siano distinte dalle minuscole, attivando le opportune opzioni

Se le funzioni sono scritte in C ma incorporano parti di codice in assembler, è opportuno prestare particolare attenzione alle istruzioni che referenziano i parametri formali (e soprattutto i puntatori): per un esempio vedere pag.  . Maggiori dettagli sull'interazione tra C ed assembler si trovano a pagina  e seguenti.

Qualche raccomandazione in tema di variabili globali . Quando si scrive un gruppo di funzioni che per lo scambio reciproco di informazioni utilizzano anche variabili globali, è opportuno che queste siano dichiarate static se non devono essere referenziate dal programma che utilizza quelle funzioni: in tal modo si accentua la coerenza logica del codice, impedendo la visibilità delle variabili 'ad uso riservato' all'esterno del modulo oggetto che contiene le funzioni. Esempio:

static int commonInfo;             // visibile solo in f_a(), f_b() e f_c()


void f_a(int iParm)



int f_b(char *sParm)



int f_c(char *sParm,int iParm)


E' però indispensabile che tutte le funzioni che referenziano dette variabili siano definite nel medesimo file sorgente in cui quelle sono dichiarate.

Considerazioni analoghe valgono anche per le funzioni: una funzione implementata unicamente come subroutine di servizio per un'altra può essere dichiarata static (e resa invisibile all'esterno del modulo oggetto) purché definita nel medesimo sorgente di questa.

Attenzione, però: se una variabile globale (o una funzione) deve essere referenziabile dal programma che utilizza la libreria, essa non deve assolutamente essere dichiarata static

Qualche precauzione è richiesta anche nella gestione dei puntatori. Non va dimenticato che i puntatori non dichiarati esplicitamente near far o huge (pag.  ) sono implementati dal compilatore con 16 o 32 bit a seconda del modello di memoria (pag.  ) utilizzato; analoga regola si applica inoltre alle funzioni (pag.  ). Ne segue che solo le funzioni dichiarate far, che accettano quali parametri e restituiscono puntatori esplicitamente far possono essere utilizzate senza problemi in ogni programma, indipendentemente dal modello di memoria con il quale esso è compilato.

Al proposito, è regola generale scrivere le funzioni senza tenere conto del modello di memoria e generare diversi file di libreria, uno per ogni modello di memoria a cui si intende fornire supporto (è necessario, come si vedrà tra breve, compilare più volte i sorgenti). Si noti che i compilatori C sono accompagnati da una dotazione completa di librerie per ogni modello di memoria gestito.

Si è detto, poco fa, che una libreria è, dal punto di vista tecnico, un file contenente più moduli oggetto, ciascuno originato dalla compilazione di un file sorgente. Durante la fase di linking vengono individuati, all'interno della libreria, i moduli oggetto in cui si trovano le funzioni chiamate nel programma e nell'eseguibile in fase di creazione è importata una copia di ciascuno di essi. Ciò significa che se una funzione è chiamata più volte, il suo codice compilato compare una volta sola nel programma eseguibile; tuttavia, se un modulo oggetto implementa più funzioni, queste sono importate in blocco nell'eseguibile anche qualora una sola di esse sia effettivamente utilizzata nel programma. Appare pertanto conveniente, a scopo di efficienza, definire in un unico sorgente più funzioni solo se, per le loro caratteristiche strutturali, è molto probabile (se non certo) che esse siano sempre utilizzate tutte insieme. Ad esempio, tutte le subroutine di servizio di una funzione dovrebbero essere definite nel medesimo sorgente di questa: ciò minimizza il tempo di linking senza nulla sottrarre all'efficienza del programma in termini di spazio occupato.

La realizzazione pratica

A complemento delle considerazioni teoriche sin qui esposte, vediamo quali sono le operazioni necessarie per la costruzione di una libreria di funzioni.

In primo luogo occorre scrivere il codice ed effettuare il necessario debugging, ad esempio aggiungendo al sorgente una main() che richiami le funzioni in modo da testare, nel modo più completo possibile, tutte le caratteristiche implementate. Al termine della fase di prova bisogna assolutamente ricordarsi di eliminare la main(), in quanto nessuna libreria C può includere una funzione con tale nome.

Nell'ipotesi di avere realizzato un gruppo di sorgenti chiamati, rispettivamente, MYLIB_A.C MYLIB_B.C MYLIB_C.C e MYLIB_D.C, accompagnati dallo header file MYLIB.H, si può procedere, a questo punto, alla generazione dei moduli oggetto e della libreria; le operazioni descritte di seguito dovranno essere ripetute per ogni modello di memoria (eccetto il modello tiny, che utilizza le medesime librerie del modello small). Negli esempi che seguono si propone la costruzione della libreria per il modello large.

Si parte sempre dalla compilazione dei sorgenti: dal momento che non si vuole generare un programma eseguibile, ma solamente i moduli oggetto, è necessaria l'opzione ‑c sulla riga di comando del compilatore

bcc -c -ml mylib_a.c mylib_b.c myliv_c.c mylib_d.c

L'opzione ‑ml richiede che la compilazione sia effettuata per il large memory model; l'operazione produce, in assenza di errori, i moduli oggetto MYLIB_A.OBJ MYLIB_B.OBJ MYLIB_C.OBJ e MYLIB_D.OBJ

E' ora possibile generare il file di libreria mediante la utility TLIB (o LIB, a seconda del compilatore utilizzato):

tlib mylibl /C +mylib_a +mylib_b +mylib_c +mylib_d

L'opzione /C richiede che la generazione della libreria avvenga in modalità case‑sensitive. Il nome file libreria è MYLIBL.LIB; se non esiste esso è creato e vi sono inseriti i quattro moduli oggetto preceduto dall'operatore ' '. Si noti che il nome del file deve essere differenziato per ogni modello di memoria; è pratica comune indicare il modello supportato mediante una lettera aggiunta in coda al nome (S per small e tiny, M per medium, C per compact, L per large, H per huge). L'estensione è, per default, .LIB

Il pacchetto di libreria completo è perciò costituito, in definitiva, dal file MYLIB.H, unico per tutti i modelli di memoria, e dai file MYLIBS.LIB MYLIBM.LIB MYLIBC.LIB MYLIBL.LIB e MYLIBH.LIB. E' ovvio che la libreria può essere pienamente utilizzata da chi entri in possesso dei file appena elencati (e della documentazione!), senza necessità alcuna di disporre anche dei file sorgenti.

Va infine sottolineato che la utility TLIB permette anche di effettuare operazioni di manutenzione: se, ad esempio, a seguito di modifiche si rendesse necessario sostituire all'interno della libreria il modulo mylib_a con una differente versione, il comando

tlib mylibl +- mylib_a

raggiunge lo scopo. Si noti che, nonostante l'operatore '+' sia specificato prima dell'operatore '‑', l'operazione di eliminazione è eseguita sempre prima di quella di inserimento. L'operatore ' ' consente di estrarre dalla libreria una copia di un modulo oggetto: il comando

tlib mylibl *mylib_a

genera il file MYLIB_A.OBJ, sovrascrivendo quello che eventualmente preesiste nella directory.

Per una descrizione completa della utility di manutenzione delle librerie si rimanda comunque alla documentazione fornita con il compilatore.




 Si tratta della Notazione Ungherese, così detta dalla nazionalità del suo inventore C. Simonyi. E', tra l'altro, la convenzione utilizzata per i simboli in ambiente Microsoft Windows.

 Dal momento che l'assembler è un linguaggio case‑insensitive, è improbabile che tali opzioni siano attive per default.

 Eccetto i casi in cui sia necessario implementare il codice in maniera dipendente proprio dal modello di memoria, utilizzando la compilazione condizionale: ancora una volta si rimanda all'esempio di pagina  , nonché a pag. 

 La sintassi descritta negli esempi è quella del compilatore Borland. Per altri compilatori è opportuno consultare la documentazione con essi fornita.

Scarica gratis Scrivere funzioni di libreria
Appunti su:



Scarica 100% gratis e , tesine, riassunti



Registrati ora

Password dimenticata?
  • Appunti superiori
  • In questa sezione troverai sunti esame, dispense, appunti universitari, esercitazioni e tesi, suddivisi per le principali facoltà.
  • Università
  • Appunti, dispense, esercitazioni, riassunti direttamente dalla tua aula Universitaria
  • all'Informatica
  • Introduzione all'Informatica, Information and Comunication Tecnology, componenti del computer, software, hardware ...