Subroutine, ovvero divagazioni tra Fortran e C

Tutto è partito da qui:

click

Allora provo a rimediare.

Il Fortran è stato il primo linguaggio di programmazione “umano”. Prima c’era solo l’assembler –si dovrebbe dire assembly.

Come linguaggio non era malaccio –buona la prima, si direbbe nel cinema– e si è espanso e imposto tanto che quando ho cominciato io sui computer normali c’era solo quel compilatore. O volete prendere in considerazione i gestionali che usavano il Cobol? dai siamo seri 8)

Uno dei vantaggi del Fortran è che il programma può essere suddiviso in parti e queste ultime possono essere scritte e compilate separatamente. E si mettono insieme solo al momento del linkaggio, per produrre l’eseguibile.

Quindi c’è un main (non ricordo se allora si chiamasse così) e tante altre procedure, pezzi. Si chiamano subroutine. A dire il vero c’è anche un altro tipo di procedura, la funzione, ma per ragioni che non ho mai capito i Veri Programmatori Fortran preferivano la subroutine.

Io che sono un cerchiobottista (in questo campo) vedrò di illustrarle entrambe. E proporrò una versione in C, per illustrare una grossa differenza tra i due approcci.

Non è una guida o un corso, mi limito a rispondere a un quesito, intesi nèh 8)

c1234567
       program demo

       i = 1
       j = 10
       r = 3.14
       write(*,*) "main - prima", i, j, r
       call duplica(i, j, r)
       write(*,*) "main - dopo ", i, j, r

       end

**********************************************

       subroutine duplica(ip, jp, rp)
       write(*,*) 'duplica - prima', ip, jp, rp
       ip = ip * 2
       jp = jp * 2
       rp = rp * 2
       write(*,*) 'duplica - dopo ', ip, jp, rp

       end

Chiaro vero? OK! In Fortran non è che si può scrivere come ti pare e piace (n.b.: adesso sì, si chiama free format ma è una cosa nuova, del 1995) ci sono un paio di regole:

  • un C o un * in colonna 1 indica che la riga è un commento;
  • nelle colonne 1-5 puoi mettere una label numerica (numeri da 1 a 99999); i numeri, arbitrari, servono per i cicli, i goto (e altri salti) e altro ancora;
  • il codice è tra le colonne 7 e 72, comprese, il resto viene ignorato;
  • la colonna 6 è riservata alla continuazione di un’istruzione troppo lunga; per dire che la riga è una continuazione della precedente bisogna mettere qualsiasi carattere tranne il blank e lo zero.

write(*,*) seguito da variabili significa scrivi sullo standard output (primo *) nel formato di default (secondo *).

La chiamata alla subroutine si fa con call <nome della subroutine> seguita dai parametri che si vogliono passare.
La subroutine stessa è esattamente come il main ad eccezione dell’intestazione: subroutine <nome della subroutine>.

Nelle versioni dal 77 in poi le stringhe possono essere delimitate sia da apici semplici che doppi. Prima non c’erano. Ma ogni variabile poteva essere vista come caratteri e quindi era come se ci fossero, discorso lungo…

In genere non si definisce il tipo delle variabili, se si usa la regola predefinita: sono tutte float (in gergo real*4) tranne quelle il cui nome inizia con una lettera compresa tra I e N (come INteger).

Proviamo a compilare e eseguire

Chiaro no? Sì, capita una cosa strana, difforme dal C 8)
Per chi ancora non l’ha vista ecco il codice C equivalente

#include <stdio.h>

void duplica(int ip, int jp, float rp);

void main() {
    int i = 1, j = 10;
    float r = 3.14;
    printf("main - prima %d %d %f\n", i, j, r);
    duplica(i, j, r);
    printf("main - dopo  %d %d %f\n\n", i, j, r);
}

void duplica(int ip, int jp, float rp) {
    printf("duplica - prima %d %d %f\n", ip, jp, rp);
    ip *= 2;
    jp *= 2;
    rp *= 2;
    printf("duplica - dopo  %d %d %f\n", ip, jp, rp);
}

compilando ed eseguendo si ha

Trovato? Troppo facile, vero? In Fortran tutti i dati vengono passati per riferimento, nel C (e credo dappertutto) per valore. OK! discorso lungo, non è questa la sede, dai! 8)

Si era parlato anche di funzioni, ecco un esempio

c1234567
       program demo
       common /mieidati/ ivar, fvar

       ivar = 100
       fvar = 2.7818
       write(*,*) "main - prima ", ivar, fvar, k
       k = myfunc(8)
       write(*,*) "main - dopo  ", ivar, fvar, k

       end

**********************************************

       function myfunc(n)
       common /mieidati/ i, f
       write(*,*) 'in myfunc - prima', n, i, f
       i = i + n
       f = f + n
       write(*,*) 'in myfunc - dopo ', n, i, f
       myfunc = n * n

       end

La chiamata alla funzione è quella usuale, la definizione è: function <nome della funzione>. Notare la sintassi per il valore ritornato, diversa da quella cui siamo abituati. In fortran esiste return ma non è lo stesso del C: abbandona immediatamente la procedura corrente.

Nell’esempio c’è ancora una cosa da notare: il common. Il common, croce e delizia del Fortran, permette di gestire le variabili che conservano il loro valore attraverso le varie procedure. Perché la cosa sia flessibile (ricordare che possiamo compilare separatamente i vari file componenti il programma) non conta il nome della variabile ma la sua posizione. Nel caso in oggetto nel main i primi 4 byte del common sono occupati dalla variabile ivar nel main e i nella funzione. Chiaro? Fate attenzione che parecchi casini verranno da questo punto, avvisati, nèh!

Compiliamo ed eseguiamo

Notare che non avendo assegnato alcun valore alla variabile k abbia un valore casuale nella prima write.

In C abbiamo

#include <stdio.h>

int myfunc(int n);
float f;

void main() {
    int k;
    f = 2.7818;
    printf("main prima %d %f\n", k, f);
    k = myfunc(8);
    printf("main dopo  %d %f\n", k, f);
}

int myfunc(int n) {
    printf("in myfunc %d %f\n", n, f);
    f = f + n;
    return n * n;
}

che ci da

In questo caso l’equivalente del common è di definire le variabili globalmente. Sì, lo so, lo so! questo è solo un approccio elementare.

A questo punto entrerebbero in scena puntatori, indirizzi e quant’altro. Ma no, mi fermo qui: credo di aver risposto alla domanda di Alessio e Francesco –sempre che qualcuno mi abbia seguito fin qui 8)

Questo post fa parte di una nuova categoria “La Pagina della Sfinge“, mica si riesce sempre a scrivere cose sensate ma superseriose 😉 e notare che ho l’approvazione del dr.prof., qui 8)

Posta un commento o usa questo indirizzo per il trackback.

Commenti

  • Mattux  Il 2 novembre 2011 alle 12:16

    Post molto interessante (come sempre del resto), Non avevo mai visto codice scritto in Fortran 😀

  • piero patteri  Il 2 novembre 2011 alle 12:37

    Nessun altro commento ?
    Brutta cosa.. per me è come se un biologo avesse scritto un post sui giochi da spiaggia dei dinosauri e fossi rimasto l’ unico a ricordare le regole delle prime partite con gli anfibi appena arrivati sulla terraferma.
    In attesa del meteorite, mi spremo le meningi, con l’ aiuto del “IBM System/360 and System/370 FORTRAN IV Language’ edizione maggio 1974. Non starò a distinguere tra le modifiche apportate dal F77 o F95, anche perchè non ho imparato sistematicamente quelle versioni come avevo invece fatto con il FORTRAN IV.
    Nel FORTRAN IV non c’ era lo statement ‘MAIN’ o simili; solo successivamente fu introdotto lo statemente PROGRAM MAIN o PROGRAM PincoPallino, per i più fantasiosi. Da notare che non c’ era distinzione tra maiuscole e minuscole, ed era anche ininfluente che gli spazi bianchi ci fossero o no.
    Di solito i programmi iniziavano on un DIMENSION NOMEARRAY(n,m,l..) e tutti gli altri statement dichiarativi, che dovevano apparire tutti prima del primo statemente eseguibile. Questo credo fosse perchè il compilatore lavorava con due passaggi, nel primo costruiva la mappa della memoria con array e variabili e le inizializzava, e poi costruiva il codice oggetto che finalmente con LINK produceva l’ eseguibile. Immagino funzioni più o meno così anche ora, ma per me, non avendo studiato informatica, era sempre una sorpresa scoprire le motivazioni logiche delle ‘ricette di programmazione’.
    Il COMMON era essenziale per trasferire dati tra routine in FORTRAN e altri linguaggi, per esempio Assembler; c’ era anche un diabolico statement EQUIVALENCE che utilizzava le stesse area di memoria assegnate p. es. a un intero lungo come array di caratteri o variabili logiche, spacchettando i bit dell’ intero… A proposito, l’ IBM usava parole composte da 4 byte da 8 bit, mentre L’ Univac, che usavano nei centri di calcolo di Roma e Napoli, aveva parole di 6 byte da 6 bit, ma da borsista ho anche visto un minicomputer (probabilmente un PDP15, ormai abbandonato) con parole da 18 bit !
    Per ora basta, o quasi…
    perchè prima dell’ END nelle routine andava il RETURN, e nel programma principale andava lo STOP.

  • juhan  Il 2 novembre 2011 alle 12:53

    L’ho detto che non né era una guida né un corso. Poi mi sono tenuto sul F77, +/- standard.
    Certo che mi sono perso il meglio (l’EQUIVALENCE) ma già lasciar intuire di dover contare i byte del common dovrebbe indurre le persone sane di mente a drizzare le orecchie, o no?
    Lo STOP e il RETURN: dissento. Ma come direbbe Pierre lo spazio per un commento è troppo breve 😉
    Gli spazi e lo zero: c’erano nella bozza poi li ho tolti per non spaventare troppo le persone sensibili.

    Al di là di queste piccolezze se vuoi ti ospitiamo per una Lectio Magistralis sul Fortran e la sua eviluzione (tu pensa che oggi scrivono in free format, la parte non eseguibile è spesso più lunga di quella eseguibile, dichiarano tutte le variabili, hanno abolito ENCODE/DECODE e altro ancora).
    Io, salvo casi sporadici, non lo uso da 3 o 4 lustri. Ma me lo sogno ancora di notte.

    • glipari  Il 2 novembre 2011 alle 15:58

      Io per fortuna (oddio fortuna…) ho saltato quella dase e ho cominciato direttamente dal Basic (ma dimmi te).

      Cmq, volevo dire che se Fortran è stato il primo, Lisp è stato il secondo, e questo vorrà pur dire qualcosa… Juhan, sei un esperto di archeologia di storia dei linguaggi di programmazione!

  • Bl@ster  Il 2 novembre 2011 alle 15:54

    Ho girato il post a father 😀
    Grazie mille, salvato su Read It Later. Sarà la mia lettura prima di nanna stasera 😉

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d blogger hanno fatto clic su Mi Piace per questo: