---------------------------------------------------------------------------- Scuola di Specializzazione in Fisica Sanitaria dell'Universita' di Bologna Marcello Galli, Anno 2006-2007 Lezioni di Informatica http://www.helldragon.eu/marcello/galli_lezioni/ ---------------------------------------------------------------------------- Esercizio: compilazione di semplici programmi Ecco un semplicissimo programma fortran, che calcola il fattoriale di un numero, la sintassi del fortran e' semplice ed il programma e' "auto-esplicativo". Lettura e scrittura dal terminale vengono effettuate con le istruzioni READ e WRITE, l'istruzione FORMAT specifica come vengono lette o scritte le variabili (specifiche di formato). Il do e' una istruzione ciclica (un loop ) , le istruzioni fra do 10 .. e 10 continue vengono eseguite piu' volte, con la variabile I che vale rispettivamente: 1, 2, ... 10 STOP ferma l'esecuzione ed END dice al compilatore che il programma principale od una routine sono finiti. ------------------------------------------------------------------------------- C SEMPLICE ESEMPIO: CALCOLO DEL FATTORIALE PROGRAM FATTORIALE WRITE(6,1000) 1000 FORMAT(' DAMMI UN NUMERO ... PER FAVORE PICCOLO ...') READ(5,*) N A=1.0 DO 10 I=1,N A=A*I 10 CONTINUE WRITE(6,3000) N,A 3000 FORMAT(' IL FATTORIALE DI: ',I5,' RISULTA: ',F15.0) STOP END ------------------------------------------------------------------------------ Compilazione e link sono fatti con: f77 -o fattoriale fattoriale.f Si esegue con: fattoriale Ecco lo stesso programma, ma scritto in C -------------------------------------------------------------------- /* semplice esempio: calcolo del fattoriale */ #include // file con descrizione funzioni standard del C #include // file con descrizione funzioni matematiche del C #include // descrizioni routines di input/output int main( int argc , char* argv[] ) { int i,n ; float a; printf(" Dammi un numero piccolo ...\n") ; scanf("%d",&n) ; /* printf(" letto %d \n",n) ; */ for ( i=1,a=1.0 ; i <= n ; i++) { a *= i ; } printf(" Il fattoriale di: %d risulta: %f \n",n,a) ; } -------------------------------------------------------------------- il programma si compila con: gcc -o fattoriale fattoriale.c si esegue con: fattoriale ------------------------- Ci sono molte differenze fra il fortran ed il C, qui se ne vedono alcune. - Il formato e' libero, ma le istruziuoni terminano con ; I commenti sono indicati con: /* commento */ blocchi di istruzioni sono delimitati da: { } - All'inizio ci sono delle istruzioni "include" , che fanno si che il compilatore aggiunga in testa al programma informazioni su come sono fate le librerie di sistema utilizzate (gli headers delle librerie). - I programmi C hanno struttura di funzioni, gli argomenti sono parametri che si possono dare quando si esegue il programma, - le variabili vanno tutte dichiarate prima dell'uso - le funzioni di input/output hanno il formato fra gli argomenti, che contiene caratteri speciali, preceduti da % o / , per indicare di andare a capo, ed il formato delle variabili - alle funzioni gli argomenti si passano "per copia", quindi per permettere alla funzione di modificare una variabile gli si deve passare il suo indirizzo: indicato con & : scanf("%d",&n) ; - notate la sintassi compatta del loop, l'operatore *= equivale ad: a= a * i ; ------------------------- L'uso di parametri forniti insieme alla chiamata al programma e' illustrato in questa variante del programma: ----------------------------------------------- /* semplice esempio: calcolo del fattoriale */ #include // file con descrizione funzioni standard del C #include // file con descrizione funzioni matematiche del C int main( int argc , char* argv[] ) { int i,n ; float a; if(argc > 1) { n=atoi(argv[1]) ; } else { printf(" Dammi un numero piccolo ...\n") ; scanf("%d",&n) ; } for ( i=1,a=1.0 ; i <= n ; i++) { a *= i ; } printf(" Il fattoriale di: %d risulta: %f \n",n,a) ; } ------------------------------------------------------------- compilate e "linkate" con: gcc -o fattoriale1 fattoriale1.c potete chiamare il programma con: fattoriale1 3 e vi dara' il risultato: 6 invece: fattoriale1 chiede un numero in input. ------------------------------------------ La shell non e' fatta per calcoli aritmetici, ad ogni modo ecco una procedura di shell per il fattoriale: Le doppie parentesi tonde e l'istruzione let indicano di considerare le espressioni come aritmetiche invece che operazioni su caratteri. ------------------------------------------------ #!/bin/bash # file fattoriale1.sh, con esempio:fattoriale per shell bash if (( $# < 1 )); then echo " uso: fattoriale1 numero " echo "manca il numero di cui calcolare il fattoriale..." exit 1 fi a=1 i=1 while (( $i < $1 )) ; do let i=i+1 let a=$a*$i done echo "il fattoriale di $1 vale $a " ---------------------------------------------- La shell e' un interprete, la sua sintassi e' piu' elementare, ad esempio le variabili vengono precedute dal carattere $ per far si che l'interprete le sostituisca con il valore corrispondente. Inoltre e' piu' lenta, siccome il programma e' semplice la cosa si vede poco, ma se fate molti giri nel loop ve ne accorgete: time fattoriale1 10000 vi da un tempo piccolo, ma non il risultato; il valore e' maggiore di quanto stia in 4 bytes. time fattoriale1.sh 10000 vi da un tempo molto maggiore, ed ancora nessun risultato. -------------------------------------------------------------- -------------------------------------------------------------- Se sul PC e' presente un debugger visule, tipo ddd (o kdgb), provatelo, compilate il programma con: gcc -O0 -g -o fattoriale fattoriale.c in modo da aggiungere al programm i simbili usati dal debugger (-g) ed evitare ottimizzazioni da parte del compilatore (-O0), poi provate : ddd fattoriale avete la possibilita' di controllare l'esecuzione riga per riga. ---------------------------------------------------------- Si puo' anche usare il debugger a linea di comando, il ddd altro non e' che un'interfaccia grafica per il gdb: gdb fattoriale si possono provare i seguenti comandi: list : mostra alcune righe del programma break 14 : l'esecuzione si fermera' alla linea 14 run : il programma inizia where : mostra dove siete step : esegue una linea print a : mostra il valore di a continue : va avanti fino alla fine ------------------------------------------------------------- Anche se non si sa nulla di assembler si puo' avere la curiosita' di dare un'occhiata a come sono fatte le istruzioni tradotte, quelle che veramente poi il PC esegue. ( Le istruzioni che il PC esegue sono in pratica le istruzioni assembler, ma tradotte in codici binari e dove al posto del call ci sono salti alle routines ) Per vedere come e' fatto l'assembler di un programma si puo' fare: gcc -O0 -S -o assembler fattoriale.c il programma, tradotto in assembler, si trova ora nel file di nome: assembler. vedete un listato del tipo: --------------------------------------- .file "fattoriale.c" .section .rodata .LC0: .string " Dammi un numero piccolo ...\n" .LC1: .string "%d" .align 32 .LC3: .string " Il fattoriale di: %d risulta: %f \n" .text ----------------------------- All'inizio vedete una sezione con, memorizzate, le stringhe di caratteri che appaiono nel vostro programma Poi c'e' il programma vero e prorio, Le istruzioni sono indicate da codici mnemonici, seguono uno o piu' argomenti; per esempio movl sposta una parola lunga, jmp .L3 e' una salto all'istruzione indicata con L3 , %eax , %epb indicano registri, fmulp moltiplica fildl , flds caricano valori, incl incrementa e cosi' via . ----------------------------- .globl main .type main, @function main: pushl %ebp movl %esp, %ebp subl $40, %esp andl $-16, %esp movl $0, %eax subl %eax, %esp movl $.LC0, (%esp) call printf leal -8(%ebp), %eax movl %eax, 4(%esp) movl $.LC1, (%esp) call scanf movl $1, -4(%ebp) movl $0x3f800000, %eax movl %eax, -12(%ebp) .L2: movl -4(%ebp), %eax cmpl -8(%ebp), %eax jle .L5 jmp .L3 .L5: fildl -4(%ebp) flds -12(%ebp) fmulp %st, %st(1) fstps -12(%ebp) leal -4(%ebp), %eax incl (%eax) jmp .L2 .L3: ---------- anche senza conoscere l'assembler si puo' individuare il loop: inizia ad .L2: il confronto e' fatto dall'istruzione cmpl , a seconda del risultato si salta ad .L5, o alla fine del loop: .L3 le istruzioni di salto sono: jle (juml less equal) oppure jmp (salta senza controllare una condizione) Si capisce subito perche', quando si puo', si evita di lavorare in assembler .... -------------------------------------------------------