Newsgroup: it.comp.lang.c
Titolo: variabili globali

Visto che certa gente si ostina a leggere i manuali alla lettera, non
reperendo le informazioni con la giusta elasticita' mentale, faccio un
esempio pratico e reale di come usare una variabile globale puo' essere
necessario.
C'era una volta un programma, nel quale vi è una funzione che viene
chiamata ogni volta che si manda un segnale d'interruzione al processo
(SIGTERM SIGINT etc), insomma un signal handler
Questo bel programma, ogni volta che viene eseguito crea delle cartelle
che andrebbero poi eliminate quando il processo termina.
E' chiaro che questa situazione implica che il processo provveda
all'eliminazione delle cartelle proprio nella funzione che intercetta il
segnale di terminazione del processo
Ma c'e' un problema: il programma potrebbe anche non aver creato le
cartelle, o averle create con un nome diverso, perchè nel file system
c'e' gia' un file con quel nome.
Qui entra in gioco la var globale, una flag o altro, nel caso in cui il
processo NON deve cancellare la cartella perchè altrimenti cancellerebbe
il file che nulla ha a che fare con il programma.
E di certo non posso passare la variabile alla funzione che intercetta il
segnale... perchè semplicemente non si puo'.
Ne segue che la cosa piu' semplice e giusta da fare è creare la
var globale, ma anzi, è addirittura l'unica soluzione!
La palla ora sta a chi dice che le globali non vanno MAI usate.

 La palla ora sta a chi dice che le globali non vanno MAI usate.
Non te la prendere.  Se frequenterai il NG per qualche tempo imparerai 
anche tu a dare il giusto peso alle affermazione di certi personaggi  ;-)
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >

anche tu a dare il giusto peso alle affermazione di certi personaggi  ;-)
E infatti è da tempo che ti ho inquadrato come un perfetto coglione al
quale non dare il minimo credito.  Il tal "fiocco", il quale non ha
coraggio, come ce l'hai tu, di firmarsi nome e cognome, si sta
guadagnando a grandi passi lo stesso titolo.

Visto che certa gente si ostina a leggere i manuali alla lettera[...]
Sei OT, cambia gruppo.

 necessario.
[...]
Un altro esempio in cui si č obbligati ad usare le variabili globali č
quando ad esempio si sviluppa un programma che deve girare su un scheda
elettronica con un microprocessore dalle risorse limitate (es. 2 KB di ROM,
64 byte di RAM, 2 MHz di clock) e ogni singolo byte (di ROM e di RAM) č
preziosissimo.
In questo caso le variabili in genere sono tutte o quasi tutte delle
variabili globali perchč pensare di passarne il valore come argomento di
funzione farebbe sě che
- quando si linka si ottiene un bel messaggio di errore che dice che hai
sforato la memoria disponibile
oppure
- in fase run-time di esecuzione il microprocessore non riesce ad eseguire
nei tempi richiesti tutte le istruzioni (ce ne sono in piů dovute ai
passaggi degli argomenti)
Le motivazioni sono diverse, ma alla fine se si guarda il sorgente C le
variabili sono dichiarate come globali.
Marco

 guadagnando a grandi passi lo stesso titolo.
Coglione sarai tu.  Ti credi al di sopra di tutti ma non sei altro che 
un maleducato.  Del resto penso che tutti abbiano te visto che ad ogni 
post diventi sempre più presuntuoso.
Ciao
Giovanni


fiocco ha scritto:




Ti consiglio di esaminare la situazione contingente ed esaminare perche'
in questo caso sei costretto ad usare una variabile globale:
Chi ti ha fornito l' interfaccia di programmazione non ha previsto che
il signal handler possa ricevere un argomento aggiuntivo e quindi ti devi
inventare un workaround. Quindi la tua condizione coatta e' figlia di
una scelta di chi ha dato le specifiche del sistema operativo o toolkit
che usi. Tale "errore storico" (no flame please: notare il virgolettato)
in Unix ha portato a definire e standardizzare un nuovo modello appunto
di gestione del signal, per bloccare un segnale mentre si modifica la var
globale e avere la garanzia di non essere interrotti dal segnal handler.
Quindi quando produci codice originale, il consiglio di evitare le
variabili
globali e' sempre valido (e ovviamente non vincolante:) )
Ciao
Roberto
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 globale e avere la garanzia di non essere interrotti dal segnal handler.
Peccato che molte volte quando si programma per un micro controllore non 
ci sia un sistema operativo vero e proprio ;-)


 il signal handler possa ricevere un argomento aggiuntivo e quindi ti devi
...scusa, forse e' colpa della mia giornata pesante, ma non ho capito 
come verrebbe passato questo argomento. Si parla della normale funz. 
signal() e relativa callback? In ogni caso, potresti postare un esempio 
piu' specifico? (possibilmente comprensibile - per non esagerare troppo 
con l'OT - anche a chi non usa Unix)
Grazie
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 preziosissimo.
vabbe'... ma questo esempio non mi sembra molto indicato.
Qui probabilmente usi il C al posto dell'Assembly (o un magari mix di C 
e ASM): gia' e' tanto che possano venir fuori programmi strutturati :)


 e ASM): gia' e' tanto che possano venir fuori programmi strutturati :)
Si, è vero, concordo.
"Usi l'assembly al posto del C", hai scritto il contrario.. ;-)

 con l'OT - anche a chi non usa Unix)
Appunto non previsto, quindi se il signal handler ha bisogno di scrutare
altri argomenti deve far accesso a variabili globali. Il modello potrrebbe
essere oggetto di critiche, ma e' questo, sia in C standard che in POSIX.
Solo in POSIX a corredo si hanno le syscall per il blocco del segnale
per non farlo capitare proprio quando tail variabili globali che servono
come espediente per passare args. vengono aggiornate. I segnale non verra'
perso, ma catturato e handler eseguito al suo successivo sblocco, nella
parte di codice dove il set di variabili globali e' stato tutto conguamente
validato.
Non credo sia molto OT: ho citato POSIX come paragone, ma in C89
(sono rimasto a quello :) ) prevede anche i signal, ma ispirati al modello
non affidabile, quello appunto che prevede che gli handler devono essere
puntatori a funzioni rientranti (in sintesi, che non accedono a var
globali)
POSIX supera questo modello e permette con la tecnica del blocco del
segnale la possibilita' dell' handler di accedwere a tali variabili.
Ciao
Roberto.


 var globale, ma anzi, è addirittura l'unica soluzione!
Non sono ancora riuscito a trovare il tempo per postarti una possibile 
soluzione... forse, piu' tardi, trovo una mezz'oretta di tempo per fare 
del codice di esempio.
PS: ma solo se questo non vada poi a generare altri flames inutili...
Ciao


 
(ovviamente sempre con i limiti del C che non e' pensato per la 
programmazione ad oggetti).
Il listato d'esempio e' composto da 3 files e si compila con qualcosa 
del genere:
# cc -o main1 main1.c sig_obj.c
Non ho scritto molti commenti (di questo mi scuso anche con tutti) ma 
ogni funzione ha solo poche istruzioni... e anche l'esempio (main1.c) 
dovrebbe rendere il tutto piu' chiaro.
Tieni presente che l'ho scritto abbastanza velocemente e, oltretutto, e' 
anche poco testato. Inoltre, ci tengo a precisare questi punti:
1) prendilo solo come "esempio" di metodo possibile.
2) il codice puo' avere bug (ma sempre benvenute correzioni e/o 
miglioramenti).
3) la gestione dei signal a me funziona, ma e' semplificata e limitata.
4) sono anche semplificate e limitate strutture dati e funzioni.
5) sig_obj.c e sig_obj.h dovrebbero essere conformi ANSI C99; main1.c no.
6) alcune condizioni d'errore non sono gestite (specialmente nel main 
d'esempio d'uso).
7) l'esempio d'uso non tratta "nello specifico" il tuo problema delle 
cartelle, ma puoi implementarlo tu stesso usando (forse) l'"oggetto" 
sig_obj.
Ciao
==============================================
/*---------------------------------------------------------*
*
*    sig_obj.h
*
*----------------------------------------------------------*/
#ifndef __SIG_OBJ_H__
#define __SIG_OBJ_H__
#define SIGOBJ_MAX_SIGNO 100 /* max signal n. = SIGOBJ_MAX_SIGNO */
typedef struct tagSigObj {
	/* strutt. e gestione semplificata (non avevo voglia x questo esempio) */
	int (*apfHandlers[SIGOBJ_MAX_SIGNO+1])(struct tagSigObj *, int, void *);
	void *apUserData[SIGOBJ_MAX_SIGNO+1];
 
} *P_SIGOBJ;
typedef int (*t_SigObjFnHandler)(P_SIGOBJ pO, int nSigNo, void *pUserData);
/* prototipi */
P_SIGOBJ SigObj_New(void);
int SigObj_SetSigHandler(P_SIGOBJ pInstance, int nSigNo, 
t_SigObjFnHandler sigObjFnHandler);
t_SigObjFnHandler SigObj_GetSigHandler(P_SIGOBJ pInstance, int nSigNo);
int SigObj_ResetSigHandler(P_SIGOBJ pInstance, int nSigNo);
int SigObj_SetUserData(P_SIGOBJ pInstance, int nSigNo, void *pUserData);
void *SigObj_GetUserData(P_SIGOBJ pInstance, int nSigNo);
void SigObj_Destroy(P_SIGOBJ pInstance);
#endif
==============================================
/*---------------------------------------------------------*
*
*    sig_obj.c
*
*----------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include "sig_obj.h"
/* ======= sez. privata ========= */
static P_SIGOBJ lcSigObj_ST(P_SIGOBJ pO, int setMode)
{	static P_SIGOBJ pOST = NULL;
	if(setMode)
		pOST = pO;
	return pOST;
}
static void lcSigObj_SignalHandler(int nSigNo)
{	P_SIGOBJ pO = lcSigObj_ST(NULL, 0);
	int nRet = 1;
	if(pO && nSigNo > 0 && nSigNo <= SIGOBJ_MAX_SIGNO && 
pO->apfHandlers[nSigNo])
		nRet = (*(pO->apfHandlers[nSigNo]))(pO, nSigNo, pO->apUserData[nSigNo]);
	if(nRet)
		signal(nSigNo, lcSigObj_SignalHandler);
}
static int lcSigObj_ValidInstance(P_SIGOBJ pInstance, int nSigNo)
{	return (pInstance && nSigNo > 0 || nSigNo <= SIGOBJ_MAX_SIGNO);
}
/* ======= interf. pubblica ====== */
/* costruttore (singleton-like) */
P_SIGOBJ SigObj_New(void)
{	P_SIGOBJ pO = lcSigObj_ST(NULL, 0);
	if(!pO)
	{	if(!(pO = malloc(sizeof(*pO))))
			return NULL;
		memset(pO, 0, sizeof(*pO));
		lcSigObj_ST(pO, 1);
	}
	return pO;
}
int SigObj_SetSigHandler(P_SIGOBJ pInstance, int nSigNo, 
t_SigObjFnHandler sigObjFnHandler)
{	if(!lcSigObj_ValidInstance(pInstance, nSigNo) || !sigObjFnHandler)
		return 0;
	if(SIG_ERR == signal(nSigNo, lcSigObj_SignalHandler))
		return 0;
	pInstance->apfHandlers[nSigNo] = sigObjFnHandler;
	return(1);
}
t_SigObjFnHandler SigObj_GetSigHandler(P_SIGOBJ pInstance, int nSigNo)
{	if(!lcSigObj_ValidInstance(pInstance, nSigNo))
		return NULL;
	return(pInstance->apfHandlers[nSigNo]);
}
int SigObj_ResetSigHandler(P_SIGOBJ pInstance, int nSigNo)
{	if(!lcSigObj_ValidInstance(pInstance, nSigNo))
		return 0;
	if(SIG_ERR == signal(nSigNo, SIG_DFL))
		return 0;
	pInstance->apfHandlers[nSigNo] = NULL;
	return(1);
}
int SigObj_SetUserData(P_SIGOBJ pInstance, int nSigNo, void *pUserData)
{	if(!lcSigObj_ValidInstance(pInstance, nSigNo))
		return 0;
	pInstance->apUserData[nSigNo] = pUserData;
	return(1);
}
void *SigObj_GetUserData(P_SIGOBJ pInstance, int nSigNo)
{	if(!lcSigObj_ValidInstance(pInstance, nSigNo))
		return NULL;
	return pInstance->apUserData[nSigNo];
}
/* distruttore */
void SigObj_Destroy(P_SIGOBJ pInstance)
{	int i;
	if(!pInstance)
		return;
	for(i = 0; i <= SIGOBJ_MAX_SIGNO; i++)
		if(!pInstance->apfHandlers[i])
			SigObj_ResetSigHandler(pInstance, i);
	lcSigObj_ST(NULL, 1);
	free(pInstance);
}
==============================================
/*---------------------------------------------------------*
*
*  main1.c - esempio d'uso di sig_obj
*
*----------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include "sig_obj.h"
/* esempio di struttura dati utente da passare ad un handler */
typedef struct tagUserDataSigInt {
	int nCount;
	/* ...... */
} UD_SIGINT, *PUD_SIGINT;
/* i signal num. dipendono dal sistema op. */
#define SIG_INT 2	/* SIGINT */
#define SIG_USR1 10	/* SIGUSR1 */
/* handler x ctrl-c */
static int sigObjHandlerSigInt(P_SIGOBJ pSigObj, int nSigNo, void 
*pUserData)
{	PUD_SIGINT pUD = pUserData;
	if(pUD)
	{	++pUD->nCount;
		printf("-- CTRL-C n. %d\n", pUD->nCount);
	}
	return 1;
}
/* handler x user-defined signal */
static int sigObjHandlerSigUsr1(P_SIGOBJ pSigObj, int nSigNo, void 
*pUserData)
{	int *pnNum = pUserData;
	if(pnNum)
	{	++*pnNum;
		printf("Signal USR1 n. %d-- \n", *pnNum);
	}
	return 0;
}
/* esempio su procedura o funzione senza parametri */
void EsempioDiRecuperoDatiDellOggettoSuProcedura(void)
{	P_SIGOBJ pSigObj = SigObj_New(); /* memo: ogg. sigleton */
	if(pSigObj)
	{	PUD_SIGINT pUD = SigObj_GetUserData(pSigObj, SIG_INT);
		if(pUD)
			printf("** Hai premuto Ctrl-C %d volte\n", pUD->nCount);
	}
}
int main(void)
{
	P_SIGOBJ pSigObj = NULL;
	UD_SIGINT UDSigInt;
	int nSCount = 0;
	int ch;
	memset(&UDSigInt, 0, sizeof(UDSigInt));
	/* creazione oggetto */	
	if(!(pSigObj = SigObj_New()))
		return -1;
	/* assegna all'oggetto l'handler per il CTRL-C e passaggio dati utente */
	SigObj_SetSigHandler(pSigObj, SIG_INT, sigObjHandlerSigInt);
	SigObj_SetUserData(pSigObj, SIG_INT, &UDSigInt);
	/* assegna all'oggetto un altro handler di esempio e passaggio dati 
utente */
	SigObj_SetSigHandler(pSigObj, SIG_USR1, sigObjHandlerSigUsr1);
	SigObj_SetUserData(pSigObj, SIG_USR1, &nSCount);
	printf("-- Premi ctrl-c o r+INVIO - q+INVIO per terminare.\n");
	while((ch = getchar()) != 'q')
	{	if(ch == 'r')
			raise(SIG_USR1);
	}
	printf("** Ho ricevuto %d signal USR1\n", nSCount);
	/* printf("** Hai premuto Ctrl-C %d volte\n", UDSigInt.nCount); */
	EsempioDiRecuperoDatiDellOggettoSuProcedura();
	SigObj_Destroy(pSigObj);
	return (0);
}
==============================================


 }


 dati)
E' vero, con la sigaction() puoi passare anche i dati, e quindi il problema 
è risolto..
(pero' prima non esisteva..)
Scusa ma il codice non l'ho visto, non c'ho proprio tempo..
Ciao 

 Scusa ma il codice non l'ho visto, non c'ho proprio tempo..
...figurati! scusa tu il disturbo... :)
ciao


 probabilmente in C.
Correggimi se sbaglio, ma l'unico modo di passare dati ad un signal handler 
è con la sigaction()
Ed è piu' efficente usare var globali piuttosto che scrivere una nuova 
chiamata di sistema solo per non usarle! 

 chiamata di sistema solo per non usarle! 
Piu' efficiente: si'. Piu' manutenibile: no. Piu' riutilizzabile: no.
Preferisci che il tuo codice sia piu' manutenibile e riutilizzabile... o 
preferisci guadagnare qualche nanosecondo in velocita'?


 preferisci guadagnare qualche nanosecondo in velocita'?
Anche qui si puo' opinare: se per qualche ragione DEVI usare le var globali
es. se usi una funzione di una libreria che riceve come arg. un puntatore
a callback de te definito a cui pero' non vengono passati argomenti de chi
la chiama e vuoi far fare a guasta piu' code, ti strutturi il codice
seguendo una buona scuola di programmazione e ti dai un protocollo da
seguire per l' uso di var globali.
potrebbero essere sufficienti solo 2 var globali:
void * argssupplementari;
size_t lunghezzaargssupplementari;
e fai in modo che le callback che definisci per accedere ad altri argomenti
accedano solo tramite questi due, con oppurtuni cast del primo.
Se sono handlers di signal, prima di settare questi valori DEVI BLOCCARE
i signal interessati con il nuovo modello di signal affidabili in modo
che non occorrano proprio a meta' modifica e leggano valori inconsistenti.
Se la circostanza e' coatta nulla osta' uso di var globali, ma se si e'
consapevoli che cio' potrebbe comportare l' abbruttimento del codice
ci si da' un' altra regola per strutturare, documentare il codice e non
perderne il controllo.


 seguire per l' uso di var globali.
ecc.


 Piu' efficiente: si'. Piu' manutenibile: no. Piu' riutilizzabile: no.
Non volevo dire efficiente, il termine giusto è conveniente
Non so se è chiara la mia obiezione: conviene riscrivere una syscall del 
genere _solo_ perchè altrimenti
si deve usare una var globale?
Se io ho da fare un progetto ed ho una scadenza, non credo proprio che 
riscriverei una funzione di sistema
perchè altrimenti userei una globale, nella prima ipotesi avrei un costo 
eccessivo!
Ciao 

> in questo caso sei costretto ad usare una variabile globale:
Ciao :)
note:
[1] questo e' diverso dal dire che alcuni dati del programma non possano 
essere accessibili globalmente.


 Ciao 
Ciao


 vengono in mente ... [1]
Un programma che richiede una configurazione un po` complessa, magari 
caricata da un file.  A meno che tu non rilegga il file ogni volta che 
serve un parametro.


 sua manutenibilita', espandibilita', affidabilita', riusabilita'....
Ottimo post :-)
Tecnico e aperto a tutte le possibilità!
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

 introdotti nello sviluppare sempre tutto di nuovo.
Questo è vero
Ciao


Interessante!
Colgo l'occasione per un ulteriore spunto
che dovrebbe essere in qualche modo simile alla
problematica che hai espresso, sperando di non
essere troppo OT.
Mi capita di avere a che fare con
schede di acquisizione dati, in ambito RADAR, che prendono
come ingresso del video che poi devo trattare
in modo 'discretizzato' o campionato.
Questi dati vengono memorizzati automaticamente
dall'hardware in grossi banchi di memoria (molti Mbyte).
Cosa altro non è questa memoria se non un dato 'globale' ?
Vista cioè come un grosso array o struct ?
Il trattamento di tali dati deve avvenire poi sotto interrupt per
motivi di sincronizzazione e trattati per comunicare
i risultati su un'altra zona di memoria (letta da un'altra
periferica o CPU).
Beh, anche questa memoria non è altro che
un grosso array condiviso, opportunamante 'semaforizzato'
per l'accesso multiplo.
C'è da considerare che in questo tipo di programmazione
tutte le risorse sono condivise dal sistema perchè non
esiste una reale gestione/protezione della memoria.
Non esiste infatti nemmeno il SO.
Esso deve essere riscritto a seconda del processore che uso.
Naturalmente una versione ultra-minima:
1) bootstrap code (C e assembler) +
2) interrupt management +
3) scheduler.
senza nemmeno il filesystem o gestione della memoria.
In questo tipo di applicazioni la cosa più importante
è quella di rispettare i tempi, soprattutto dentro
le routine di interrupt (che NON prendono argomenti!).
Quindi si usano:
(a) macro in quantità, meglio se con do {} while per convenienza
notazionale e perchè come noto chiamare funzioni
dentro gli handler sarebbe troppo inefficiente a causa del
salvataggio di tutti i registri del processore;
(b) globali (vedi memorie condivise o contatori dentro gli interrupt).
Ma anche la scrittura/lettura di un singolo registro di device
è in fondo una scrittura/lettura su una globale;
(c) quant'altro è necessario per rientrare nei tempi e per
mantenere il programma ad un livello di complessità
non astronomico (se si volesse per forza rispettare
alla lettera il manuale del programmatore provetto).
Capisco che questo è un tipo di programmazione
non convenzionale perchè molto legato
all'hardware ma comunque rappresenta un caso
di programmazione "reale" sul campo. Nemmeno
così inconsueto in fondo ...
Ricollegandomi al tuo esempio del file, hai almeno
la possibilità di usare la tecnica di rileggerlo.
Io non posso rileggere i dati acquisiti quando
voglio, lo decide solo l'HW quando i dati sono validi!
E da qualche parte li devo pur parcheggiare nell'attesa
di elaborarli.
Il problema sta proprio nella grossa mole
di questi dati da trattare poi in pochi secondi :-)


> essere accessibili globalmente.
...cioe' puoi recuperarli (i dati), volendo, in qualunque parte del 
programma, anche senza essere costretto ad usare variabili dichiarate 
globali.
Nel codice che avevo postato, in main1.c, avevo messo un esempio di 
tecnica OOP-like per recuperare il puntatore (e in quel caso anche una 
struttura dati) di un'"oggetto" singleton (vd. 
EsempioDiRecuperoDatiDellOggettoSuProcedura()).
Nel tuo caso questo "oggetto" potrebbe chiamarsi ObjMiaConfigurazione ed 
avra' tutti i "metodi" (funzioni) per leggere, scrivere, calcolare, 
verificare e recuperare i parametri di configurazione da un file 
(ovviamente tutti rimangono memorizzati su una struttura).
Ma, naturalmente, esistono anche altre possibili tecniche, meno OOP, 
pero' sempre modulari ed isolabili dal resto del programma.
Ciao


 
Io ho riportato un esempio classico che per chi usa sistemi Unix (ma e` 
altrettanto usato su Windows) e` molto familiare.
Anche io ho lavorato per molti anni scrivendo programmi per sistemi 
telefonici e molte delle cose di cui scrivi le ho affrontate 
quotidianamente.
Un sistema telefonico e` un sistema che deve elaborare eventi 
distribuiti nel tempo e nello stesso tempo supervisionare migliaia di 
processi contemporaneamente.  Per questo vengono in genere usati sistemi 
operativi "event driven" che devono associare ogni evento ad uno dei 
processi.
Ad ogni processo viene associata memoria per gestire il corretto 
evolvere del processo e questa memoria *deve* essere allocata 
globalmente per potere esistere fra un evento e l'altro.
Ho recentemente scritto un programma per gestire un proxy FTP e come 
molti protocolli anche questo e` "event driven" e senza avere delle 
variabili globali per poter gestire la sequenza degli eventi.
Forse si puo` sostenere che le variabili globali sono pericolose (anche 
se lo trovo discutibile) ma sostenere che NON devono essere usate mi 
sembra portare all'estremo il ragionamento.


 così inconsueto in fondo ...
 > .....
E allora ti devi divertire con le globali. :)
Pero' immagino che, in questi particolari casi, il software non ne 
guadagni in manutenibilita', riusabilita',...
Quindi, chi puo'...
Ciao


 guadagni in manutenibilita', riusabilita',...
Non particolarmente riusabile infatti!
Si cerca di isolare il tutto meglio che si puň, cercando di
essere lo stesso efficienti.
Personalmente ho fatto delle librerie ben suddivise per
famiglie di processori oppure delle librerie piů
strettamente ansi-C.
Con esse cerco di creare un nuovo progetto
includendo piů che posso dei file dalla
cartella 'ansi-C' e il meno possibile dalla cartella 'specific-processor'.
Tipicamente mi ritrovo piů globali o piů cose 'sporche'
proprio nella parte 'specific-processor' o 'specific-board'.


 pero' sempre modulari ed isolabili dal resto del programma.
Evidentemente sei abituato ad usare C++ od altri linguaggi OO e MAI hai 
scritto programmi RealTime. Ed ancora meno per micro-controllori.


 e MAI hai scritto programmi RealTime. Ed ancora meno per micro-controllori.
Micro-controllori no. Programmi in c e assembly (anche in real-time) 
si'. Ma non li sviluppo piu' da circa 15 anni.


 quell'altro thread del do..while?)
Sorry ho sbagliato :-(
In ogni caso ho inteso che fosse una delle ragioni per cui e` 
sconsigliato usare le variabili globali.
