Dove si parla di librerie generiche, make e altro …..
scrivere una funzione conta
di segnatura
int conta (void);
che restituisce come valore il numero di volte che e' stata invocata dall'inizio del programma, quindi 1 la prima volta, 2 la seconda etc senza utilizzare variabili globali.
Verificare che dichiarando static una funzione all'interno di un file non e' possibila invocarla da funzioni definite in altri file (suggerimento: provare a definire static
la funzione somma
dell'esempio fatto per la compilazione separata).
In questo esercizio si richiede di realizzare alcune funzioni che lavorano su liste generiche in C. Una lista generica e' rappresentata con la seguenti struct
typedef struct elem { /** chiave */ void * key; /** informazione */ struct elem * next; } elem_t; typedef struct { /** la testa della lista */ elem_t * head; /** la funzione per confrontare due chiavi */ int (* compare) (void *, void *); /** la funzione per copiare una chiave */ void * (* copyk) (void *); } list_t;
la prima struttura (elem_t
) rappresenta un nodo della lista generica. Ogni nodo contiene una chiave key
che puo' avere tipo qualsiasi.
La seconda struttura (list_t
) permette di definire una particolare lista a partire da quella generica. Per farlo bisogna fornire due funzioni:
compare
permette di confrontare due chiavi, ritorna 0 se sono uguali ed un valore diverso da 0 altrimenticopyk
crea una copia della chiave (allocando la memoria necessaria) e ritorna il puntatore alla copia (se tutto e' andato bene) o NULL (se si e' verificato un errore)Si chiede di realizzare le funzioni che permettono di creare/distruggere una lista generica e quelle per inserire ed estrarre un elemento generico. Realizzare un main di test che prova ad istanziare la lista in due versioni: una prima a valori interi usando le seguenti funzioni per il confronto e la copia:
/** funzione di confronto per lista di interi \param a puntatore intero da confrontare \param b puntatore intero da confrontare \retval 0 se sono uguali \retval p (p!=0) altrimenti */ int compare_int(void *a, void *b) { int *_a, *_b; _a = (int *) a; _b = (int *) b; return ((*_a) - (*_b)); } /** funzione di copia di un intero \param a puntatore intero da copiare \retval NULL se si sono verificati errori \retval p puntatore al nuovo intero allocato (alloca memoria) */ void * copy_int(void *a) { int * _a; if ( ( _a = malloc(sizeof(int) ) ) == NULL ) return NULL; *_a = * (int * ) a; return (void *) _a; }
e una seconda che ha come chiavi stringhe usando analoghe funzioni per la copia ed il confronto.
Sviluppare un opportuno main di test di pari passo allo sviluppo delle funzioni.
Modificare il tipo dell'esercizio 3 in modo da riuscire ad implementare anche le funzioni che scrivono su file e leggono da file una lista generica.
Sviluppare un opportuno main di test di pari passo allo sviluppo delle funzioni.
Con riferimento all es 2 della scorsa volta definire un file Makefile che contenga
lib
per generare correttamente la libreria libList.acleanall
che elimini gli oggetti e gli eseguibili
utilizzare dove possibile le regole implicite, le variabili e le convenzioni viste a lezione. Usare gcc -MM
per generare automaticamente le liste di dipendenze per i target relativi ai moduli oggetto.
Sviluppare un makefile opportuno che gestisca l'aggiornamento automatico dei file utilizzati per gli esercizi 3 e 4 di questa esercitazione e crei automaticamente la libreria corrispondente con un target “lib”.