[Lugge] Quesito biricchino di programmazione in C (birra in palio)

  • From: "Roberto A. Foglietta" <me@xxxxxxxxxxxxxxxxxxxxxx>
  • To: lugge@xxxxxxxxx
  • Date: Wed, 09 Jun 2004 11:36:35 +0200


---------------------------------------------------- Alessandro Vernassa tu sei fuori gioco perchè ti ho già comuicato la soluzione: NON FARE IL FURBO! ;-) ----------------------------------------------------

Ciao,

facciamo che io decida di fare una cosa del genere:

 #define esci(a) ret = (a); \                     [1]
                 goto RITORNA

 per ora sorvoliamo sull'opportunità di usare goto come istruzione
perchè non è questo il punto della questione, allora se faccio:

if(err) esci(err); [2]

 il compilatore non mi segnala errore ma poi accade che il programma
non funziona perchè viene interpretato in questo modo:

 if(err)                                          [3]
        ret = err;
 goto RITORNA;          //<---------DISASTRO------!!

 nonostante tutto la [2] ha una sintassi accettabile per chi scrive in
C e il compilatore nemmeno si lamenta. Però può essere davvero difficile
trovare un errore del genere specie se #define è in un .h magari
inestato in altri .h; insomma una fonte di problemi niente male!

 Certo si potrebbe convertire la [1] in una funzione ma in questo modo
il goto smetterebbe di essere utile perchè si riferisce ad un'etichetta
fuori dalla funzione. Perciò si riscrive la definizione della macro in
questo modo:

#define esci(a) { ret = (a); goto RITORNA } [4]

cosi le parentesi costringono il compilatore a fare ciò volevamo

 if(err)                                          [5]
        esci(err);
 else
        printf("ciao!\n");

 ma se compilate una cosa del genere il compilatore vi dà un errore per
via del punto e virgola in fondo ad esci:

 if(err) {                                        [6]
        ret = (a);
        goto RITORNA
 };                     //<---------ERRORE------!!
 else
        printf("ciao!\n");

 a questo punto l'unica soluzione sembra essere quella di ricordarsi
che esci è una macro e quindi non mettere il punto e virgola in fondo, e
per ricordarsi che è una macro la metto in maiuscolo:

  if(err)                                          [6]
        ESCI(err)
 else
        printf("ciao!\n");





==== (QUESITO) ====

 Ora il quesito è: <<se invece fossi ostinato e volessi scrivere
prorpio così, come la [5], confondendo la macro con una funzione? Avete
un idea di come si può fare?>>

 Io ho trovato una soluzione ed è così carina IMHO quanto altrettanto
sconosciuta che merita di essere diffusa... anche perchè pare sia una di
quelle cose che programmatori con 10/15 anni di esperienza sulle spalle
ritengono sia un limite invalicabile e si piegano al volere della
sintassi del C. Lo scopo del gioco è quello di prendersi gioco del
parser/compilatore C e lancio la sfida: una birra in palio al chi lo
scopre. Scadenza il 16 giugno 2004, fra una settimana!
 ;-)





==== (NOTA INFORMATIVA) ====

 Riguardo l'opportunità di usare goto: immaginate di avere goto che
saltano da un pezzo all'altro del codice ci si diventa scemi a fare il
debug di una codice di quel tipo per non parlare della leggibilità.
 Invece il goto usato come break multiplo di cicli while/for inestati,
usciti dai quali si va ad una procedura comune che esce dalla funzione
lasciando pulito l'enviroment delle static variable della funzione è un
trucco del tutto accettabile.
 La necessità che una funzione abbia dei parametri interni che
permangono dopo l'uscita e che fungano da memoria della stessa è
abbastanza sovente, uscire in modo pulito però a volte non è semplice.
 D'altrone mettere ordine nelle static di una funzione si può fare solo
dall'interno della funzione, perciò o si usa una macro oppure si fa una
funzione che accetta tanti puntatori a quante static sono definite...
cioè aggiungendo o diminuendo il numero si deve riscrivere l'api della
funzione e tutte le chiamate ad essa!

Mentre fare una cosa del genere:

void func(par...)
{
 static enviroment

ciclo { ciclo { ciclo { ret = -1; goto RITORNA; } } }

RITORNA:
 enviroment refresh
 return ret;
}

è molto semplice, facilmente intelleggibile, mantenibile, etc. etc.



--
Roberto A. Foglietta
http://roberto.foglietta.name
http://lugge.net
ICQ#: 108718257
========---------- Prima di scrivere in m-list per favore leggi il regolamento http://www.lugge.net/soci/index.php?link=manifesto


Archivio delle e-mail postate in lista http://www.freelists.org/archives/lugge/

Modifica dell'account sulla lista LUGGe http://www.lugge.net/soci/index.php?link=manifesto.htm#list

Other related posts: