glug: Quesito biricchino di programmazione in C (birra in palio)

Roberto A. Foglietta me@roberto.foglietta.name
Mer 9 Giu 2004 11:37:07 CEST


----------------------------------------------------
  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



Maggiori informazioni sulla lista glug