====== Esercitazione 1 ======
Dove riprendiamo il C sequenziale ed rispolveriamo alcuni strumenti utili quali //debugger preprocessori compilatori linker//. Inoltre introduciamo ''doxygen, valgrind e mtrace'' che ci aiuteranno a scrivere del codice C piu' ragionevole.
===== Esercizio -1: sul debugging =====
Usare il debugger ''gdb'' o ''ddd'' per trovare cosa non va nei seguenti {{lcs:lcs07:esercitazioni:ese-debug.tar|programmi}}
- //ese-gdb1.c// e' una soluzione completa (non funzionante) dell'esercizio percolation (vedi [[lcs:lcs07:esercitazioni:esercitazione1]] degli anni precedenti)
- //ese-gdb2.c// e' una soluzione parziale (non funzionante) dello stesso esercizio. In particolare si affronta soltanto l'allocazione e l'inizializzazione della matrice
===== Esercizio 0: Getting started -- Preprocessing, compilazione e linking =====
0.1) Compilare ed eseguire il seguente programma:
#include
#include
int main (void) {
double x=3.0;
printf("Radice = %f\n",sqrt(x));
return 0;
}
salvato nel file //ff.c// con
gcc -Wall -pedantic ff.c
Chi segnala un errore? E' fallita la fase di preprocessing, la compilazione o il linking? Cosa contine il modulo oggetto se specifico l'opzione -c? Come si risolve il problema?
0.2) Cosa accade se eliminiamo la linea
#include
? A questo punto cosa va storto? Sapete interpretare i messaggi a video e stabilire chi li ha scritti e perche'? Viene generato l'eseguibile?
0.3) Generare il modulo oggetto con
gcc -Wall -pedantic -c ff.c
Utilizzare //objdump, nm, readelf// per capire cosa contengono la tabella di rilocazione, la tabella dei simboli esportati ed esterni, le sezioni data, BSS e codice. (utilizzare il man e cercare su google).
0.4) Usare l'opzione //-E// e la //-S// del gcc: che cosa succede? Cosa accade specificando il flag -g assieme a -S?
===== Esercizio 1. Liste generiche in C =====
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 */
void * payload;
/** puntatore elemento successivo */
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 *);
/** la funzione per copiare un payload*/
void * (* copyp) (void *);
} list_t;
la prima struttura (''elem_t'') rappresenta un nodo della lista generica. Ogni nodo contiene una chiave (''key'' non e' possibile avere chiavi duplicate nella lista) e un campo di informazioni per quella chiave (''payload'').
La seconda struttura (''list_t'') permette di definire una particolare lista a partire da quella generica. Per farlo bisogna fornire tre funzioni:
* ''compare'' permette di confrontare due chiavi, ritorna 0 se sono uguali ed un valore diverso da 0 altrimenti
* ''copyk,copyp'' -- creano una copia di una chiave o un payload (allocando la memoria necessaria) e ritornano il puntatore alla copia (se tutto e' andato bene) o NULL (se si e' verificato un errore)
Si chiede di realizzare alcuni funzioni per manipolare la lista generica ed un main che ne testi il funzionamento.
Nel file tar-file {{:informatica:sol:laboratorio:esercitazioni:ese1.tar|}} potete trovare il file ''genList.h'' con le definizioni delle strutture dati e dei prototipi delle funzioni richieste. I commenti all'interno del file sono in fomato doxygen. Sempre nel tar e' presente il file ''Doxyfile'' che pilota la generazione della documentazione fomato HTML. Per generarla basta invocare
bash$ doxygen
e poi visualizzare il file ''../html/index.html'' con un browser.
===== Esercizio 2. Liste generiche analizzate =====
Utilizzare la funzione ''mtrace()'' e l'utility ''mtrace'' per verificare i leak di memoria nel programma sviluppato nell'esercizio 1.
Utilizzare l'utility valgrind per controllare la mancata inizializazzione di variabili, le scritture/letture in aree non allocate, i leak di memoria e altro. Ad esempio:
$ valgrind --show-reachable=yes --leak-check=full --leak-resolution=high -v ./exe params
dove (''exe params'' e' il nome del vostro eseguibile di test con gli eventuali parametri) e analizzare le risposte.