Newsgroup: it.comp.lang.c
Titolo: Struttura con array di dimensione variabile

Ho un algoritmo che implementa un filtro numerico scritto in due 
classici file:
   filter.c
   filter.h
L'interfaccia di questo modulo è formata da due sole funzioni:
   void filter_init(Filter *f);
   int filter(Filter *f, int value);
La prima funzione inizializza il tipo Filter utilizzato dall'algoritmo e 
la seconda funzione ritorna il nuovo valore all'uscita del filtro 
passando come argomento il nuovo valore in ingresso.
In un mio programma devo implementare diversi filtri, diciamo 2. La cosa 
sembra semplice:
---
   Filter f1, f2;
   const int values1[] = {....};
   const int values2[] = {....};
   filter_init(&f1);
   filter_init(&f2);
   for (i = 0; i < sizeof(values1)/sizeof(values1[0]); i++) {
     filter(&f1, values1[i]);
   }
   for (i = 0; i < sizeof(values2)/sizeof(values2[0]); i++) {
     filter(&f2, values2[i]);
   }
--
Tutto questo è molto bello, a parte il fatto che vorrei utilizzare due 
filtri con una profondità (o lunghezza del filtro) diversa tra di loro. 
L'informazione sulla lunghezza del filtro è implicita nella struttura 
Filter:
--- filter.h
   typedef struct {
     struct FilterElement buffer[FILTER_LENGTH];
     ...
   } Filter;
---
Come faccio per rendere generico l'algoritmo in termini di lunghezza del 
filtro? Semplicemente potrei utilizzare nella struttura Filter un 
puntatore ad un buffer anzichè un array statico e aggiungere un campo di 
lunghezza:
--- filter.h
   typedef struct {
     struct FilterElement *buffer;
     int filter_length;
     ...
   } Filter;
---
Nel chiamante, però, dovrei fare qualcosa del genere:
---
   struct FilterElement values1[FILTER1_LENGTH];
   struct FilterElement values2[FILTER1_LENGTH];
   Filter f1, f2;
   filter_init(&f1, values1, FILTER1_LENGTH);
   filter_init(&f2, values2, FILTER2_LENGTH);
---
Come si vede, sono costretto ad "esternare" la struttura FilterElement 
che il chiamante potrebbe non conoscere per i suoi scopi e la 
filter_init si complica perchè gli devo passare il puntatore all'array e 
la sua lunghezza.
Vedete altre alternative nel mondo embedded dove non posso usare malloc()?


typedef struct {
    struct FilterElement buffer[MAX_FILTER_LENGTH];
    int actual_length;
} Filter;
Filter f1, f2;
filter_init(&f1, FILTER1_LENGTH);
e volendo aggiungi una funzione d'interfaccia al modulo tipo:
int filter_getLength(Filter* s);
che ritorna la lunghezza che ha nella struttura. ;-)
Ciao!

 filter_init(&f1, FILTER1_LENGTH);
Ho deciso di variare la profondità del filtro per i due segnali
proprio per
diminuire l'occupazione in RAM dei filtri.
L'esempio è di soli due segnali, ma nella mia applicazione ne ho 16.
sizeof(struct FilterElement)=4 e MAX_FILTER_LENGTH=13, quindi avrei
  16*4*13 = 832byte
una enormità nel mio processore!!! Inoltre, solo alcuni segnali sono
parecchio
rumorosi e necessitano di filtri di profondità 13, per gli altri mi
potrebbe bastare
anche da 5 o 7.


uhm.. in questo caso non ti salvi di molto.. se sai la dimensione
massima della _somma_ dei filtri, al massimo
static struct s_FilterElement[ALL_FILTERS];
static int s_last_FilterElement;
typedef struct {
    struct *FilterElement buffer;
    int actual_length;
} Filter;
Filter f1, f2;
filter_init(&f1, FILTER1_LENGTH);
filter_init(&f1, FILTER2_LENGTH);
con
void filter_init(Filter* f1, int len)
{
   [...]
    f1->buffer = s_FilterElement+s_last_FilterElement;
    f1->actual_length = len;
    s_last_FilterElement += len;
   [...]
}
Ciao!

 [...]
Sì, questa è una possibilità.
A me ne stavano venendo altre due, una peggio dell'altra :-)
--- filter.h
typedef ... FilterElement;
typedef struct {
  struct FilterElement *buffer;
  ...
} Filter;
#define DEFINE_FILTER(f, n)  struct FilterElement f ## _buffer[n];
Filter f = { f ## _buffer };
---
--- main.c
DEFINE_FILTER(f1, 13);
DEFINE_FILTER(f2, 5);
---
Non mi piace perchè non potrei fare cose del tipo:
  static DEFINE_FILTER(f1, 13);
Un'altra possibilità è quella di prendere in giro il compilatore per
creare una struttura con
un ultimo campo a dimensione variabile:
--- filter.h
typedef struct {
  int n;
  ...
  struct FilterElement buffer;
} Filter;
#define DEFINE_FILTER(f, n) struct {int n; ...; struct FilterElement
buffer[n];} f = {n};
---
--- filter.c
void filter_init(Filter *f) {
  memset(&f->buffer, 0x00, f->n);
  ...
}
void filter(Filter *f, int value) {
  ((struct Filter Element *)&f->buffer)[...]
}
---
--- main.c
...
DEFINE_FILTER(f1, 13);
DEFINE_FILTER(f2, 5);
...
filter_init((Filter *)&f1);
filter_init((Filter *)&f2);
...
filter((Filter *)&f1);
---
Il trucco è accedere all'array in fondo alla struct con
  ((struct FilterElement *)&f->buffer)[...]
essendo sicuri che f->buffer è in realtà un array di f->n elementi.
Naturalmente le cose che non mi piacciono di questo approccio:
- troppo delicato giocare con i puntatori in questo modo
- l'applicazione chiamante deve utilizzare DEFINE_FILTER,
  ma può scrivere qualcosa del tipo
    static const DEFINE_FILTER(f1, 13)
- l'applicazione chiamante deve forzare un cast per passare
  il parametro Filter.
Che ne dite?

 Un'altra possibilità è quella di prendere in giro il compilatore per
Mai prendere in giro il compilatore: tra tutti, è l'ultimo che
vorresti vederti contro! ;-)
Ciao!

 vorresti vederti contro! ;-)
In effetti... :-)
In realtà mi sono fatto ispirare ad una nuova feature del C99 e cioè
ai variable length arrays. Vabbè, evito.