Si vuole scrivere un programma che calcola la somma dei valori senza segno a 32 bit contenuti in un file, ignorando eventuali byte finali resto della divisione per 4, se la lunghezza del file in byte non è divisibile per 4. La lettura deve avvenire 4 byte alla volta.
La funzione deve essere incapsulata nel file E1-sum/e1.c
in int sum(const char* filename, unsigned long *psum)
che prende il nome di un file e l’indirizzo di una variabile dove scrivere il numero calcolato.
Una sessione di uso basata sul file e1_main.c
fornito potrebbe essere:
E1-sum > gcc e1_main.c e1.c -o e1
E1-sum > ./e1
Sintassi: ./e1 filename
E1-sum > ./e1 README
Somma: 1D31E8B07E
E1-sum >
Il codice è munito di soluzione in E1-sum/sol. Per generare sia la versione studente che quella corretta di riferimento si può usare make
, dove E1-sum/e1
è la versione studente e E1-sum/e1-sol
è quella docente.
Lo scopo dell’esercizio è quello di scrivere file binari con la seguente struttura composti da numeri pseudo-casuali:
0 |magic number|
4 | size |
8 | rnd 1 |
12 | rnd 2 |
16 | ... |
Il magic number deve essere 0xEFBEADDE per tutti i file generati con questo programma. I magic number sono codici associati ai tipi di file, specialmente se binari, per identificarli univocamente al momento dell’apertura, e sono disposti all’inizio del file. Il magic number è considerato a scopo di appredimento. SUbito dopo c’è il numero di valori casuali del file.
Si richiede di scrivere nel file E2-make-rnd-file/e2.c
una funzione int make_rnd_file(int size, int seed, int mod, char *filename);
con i seguenti parametri:
Compilare con e2_main.c e2-sol.c -o e2-sol
(oppure usando make
). Il programma genera il file a partire dai dati forniti da riga di comando. Ad esempio, per generare un file chiamato test.dat
con 1000 valori pseudo-casuali inferiori a 10 con seme 5651 si digita:
> ./e2-sol test.dat 1000 10 5651
Risultato: 1/1
Si consiglia di esplorare anche il file creato anche con il programma xxd
:
> xxd test.dat | head
00000000: dead beef e803 0000 0700 0000 0800 0000 ................
00000010: 0000 0000 0100 0000 0000 0000 0300 0000 ................
00000020: 0900 0000 0600 0000 0700 0000 0200 0000 ................
00000030: 0100 0000 0000 0000 0700 0000 0700 0000 ................
00000040: 0300 0000 0200 0000 0300 0000 0800 0000 ................
00000050: 0800 0000 0300 0000 0000 0000 0900 0000 ................
00000060: 0300 0000 0800 0000 0300 0000 0400 0000 ................
00000070: 0600 0000 0300 0000 0600 0000 0100 0000 ................
00000080: 0900 0000 0700 0000 0100 0000 0100 0000 ................
00000090: 0700 0000 0500 0000 0400 0000 0100 0000 ................
Si noti che letto in little-endian il magic code 0xEFBEADDE
è dead beef
, la mascotte esadecimale del corso. Si noti inoltre che i successivi 2 byte sono e803 che, essendo riportati nel file in formato little-endian rappresentano 0x03e8, cioè 1000 in base 10.
Ottimizzare la soluzione dell’esercizon T1
leggendo a blocchi di 4KB e non a word di 32 bit.
P8> cd E3-sum-opt
P8/E3-sum-opt> dd if=/dev/random of=file.txt count=8192 bs=4096 <---- crea file di 8192*4096 ~ 34KB random
P8/E3-sum-opt> time ./e3 file.txt <---- misura tempo versione ottimizzata (E3)
P8/E3-sum-opt> time ../E1-sum/e1 ../E1-sum/file.txt <---- misura tempo versione originaria (E1)
Scrivere nel file E4-file-eq/e4.c
una funzione int file_eq(char* f1, char* f2)
che, dati i percorsi di due file f1
e f2
, restituisce zero se i file sono uguali, un valore maggiore di zero se i file sono diversi, e -1 in caso di errore.