Newsgroup: it.comp.lang.c
Titolo: Array con indici mnemonici

In un sorgente C devo inizializzare un array di struct con circa
50-100 record. Naturalmente faccio qualcosa del genere:
--- sorgente.c ---
  struct mystruct {
    { c11, c12, ..., c1n },
    { c21, c22, ..., c2n },
    ...
    { cm1, cm2, ..., cmn },
  } myarray;
---
m è il numero di record, n è il numero dei campi della struct
mystruct.
Anche altri sorgenti devono accedere a questo array, quindi inserisco
nel file sorgente.h sia la definizione della struttura sua la
dichiarazione extern.
Vorrei, però, accedere all'array indicando un indice mnemonico,
piuttosto che un indice numerico. Così creo, sempre nel file
sorgente.h, una enumerazione:
--- sorgente.h ---
  struct mystruct {
    tipo1 campo1;
    tipo2 campo2;
    ...
    tipon campon;
  };
  extern struct mystruct myarray[];
  enum MYSTRUCT {
    NOME_RECORD1 = 0,
    NOME_RECORD2,
    ...
    NOME_RECORDm,
  };
---
In questo modo, in un altro file sorgente potrei scrivere:
  if( myarray[NOME_RECORD1].campo1 == valore )
    ...
che è molto meglio rispetto a scrivere myarray[34].campo1.
Il tutto funziona egregiamente, ma non mi convince la leggibilità e
manutenibilità del codice. Stiamo parlando di circa 50 record. Se
dovessi cancellare un record, oppure spostare l'ordine di alcuni
record nella inizializzazione, dovrei ogni volta ricordarmi di
modificare conseguentemente il file .h.
Esiste la possibilità di legare in qualche modo l'enum nel file .h e
l'inizializzazione nel file .c?
Oppure esiste un metodo più elegante per fare quello che voglio io?

 l'inizializzazione nel file .c?
Ho scoperto da poco che puoi inizializzare un array o una struct 
indicando esplicitamente gli indici (dovrebbe essere un qualche standard 
ma non l'ho mai utilizzato). La sintassi dovrebbe essere
int array[10]={
   [2]=2,
   [3]=5};
per le struct dovrebbe essere:
struct {
   int pippo;
   int pluto;
    } struttura = {
   .pippo=4;
   .pluto=3;
};
Mi pare che sia esattamente quello che ti serve, ma dovrai fare delle 
prove o cercare altri riferimenti.
E.

 ma non l'ho mai utilizzato). La sintassi dovrebbe essere
Purtroppo il compilatore che uso non accetta quella nuova sintassi (mi
sa che dovrebbe chiamarsi C99 o qualcosa del genere).
Comunque sia, non penso che possa aiutarmi più di tanto... ma forse
sbaglio. Il problema
è che non posso utilizzare quella via.


Allora probabilmente la soluzione migliore è leggere i valori in runtime 
da un file esterno. Ma perché non puoi utilizzare quel metodo? Non puoi 
usare gli mnemonici della enum nella inizializzazione? Eventualmente 
potresti usare delle vere costanti definite con #define.
E.

 potresti usare delle vere costanti definite con #define.
Non posso inizializzare usando la sintassi C99 perchè il compilatore è
vecchio e non posso cambiarlo. Devo usare il C originale.
Forse con qualche giochino del preprocessore si riesce...

Mi pare di capire che tu voglia realizzare un array associativo.
Forse le librerie riportate qui ti possono dare un'idea:
http://en.wikipedia.org/wiki/Associative_array#C
Perņ, dato il tuo caso, ipotizzo avrai dei vincoli di risorse 
ed efficienza che renderanno sconveniente questo approccio.
Ciao.

 ed efficienza che renderanno sconveniente questo approccio.
Decisamente...

 da un file esterno. 
Anzi viceversa. La tua soluzione è fare un piccolo programmino esterno 
che ti genera i sorgenti che poi vai a compilare. Il programmino si 
preoccupa di mantenere la coerenza tra le enum e le definizioni degli 
array. Sempre che tu non riesca a farlo fare al preprocessore...
E.

 array. Sempre che tu non riesca a farlo fare al preprocessore...
Ci avevo pensato, solo che vorrei evitare questa soluzione... meglio
se riesco a farlo con il preprocessore.

 l'inizializzazione nel file .c?
[..]
potresti usare anche delle semplici define..
#define FIELD_ONE       0
#define FIELD_TWO       1
#define FIELD_THREE     2
..
struct mystruct {
        tipo1 campo1;
        tipo2 campo2;
        ...
        tipon campon;
};
extern struct mystruct myarray[];
if (mystruct[FIELD_ONE].campo1 == valore) {}
--
www.iuz-lab.info

 if (mystruct[FIELD_ONE].campo1 == valore) {}
Ma non risolverei il problema. Anzichè tenere coerenti la enumerazione (nel .h) 
e la inizializzazione (nel .c), in questo caso dovrei tenere coerenti le #define 
(nel .h) e la inizializzazione (nel .c).

(nel .h) e la inizializzazione (nel .c).
#define PERE NUM_PERE
#define MELE NUM_MELE
//#define BANANE NUM_BANANE
#define FRAGOLE NUM_FRAGOLE
typedef struct
	{
	int campo1;
	char campo2;
	long campo3;
	int campo4;
	} mystruct;
enum MYSTRUCT_OBJ
	{
	NUM_PERE = 0,
	NUM_MELE,
	NUM_BANANE,
	NUM_FRAGOLE,
	ULTIMO,
	};
mystruct myarray [ULTIMO];
#ifdef PERE
 #define Pere myarray[NUM_PERE]
#endif
#ifdef MELE
 #define Mele myarray[NUM_MELE]
#endif
#ifdef BANANE
 #define Banane	myarray[NUM_BANANE]
#endif
#ifdef FRAGOLE
 #define Fragole myarray[NUM_FRAGOLE]
#endif
Pere.campo1 = 1;
Mele.campo2 = 'A';
Fragole.campo3 = 12345;

io ho usato questa tecnica:
crei un file con tante righe come queste
file "pippo.def":
---
MACRO( SIMBOLO1,valoreIniziale1 )
MACRO( SIMBOLO2,valoreIniziale2 )
MACRO( SIMBOLO3,valoreIniziale3 )
...
MACRO( SIMBOLOn,valoreInizialen )
---
poi nell'header inserisci questo:
---
#undef MACRO
#define MACRO(sym,val)  sym,
enum SIMBOLI
{
#include "pippo.def"
};
---
e dove dichiari l'array:
---
#undef MACRO
#define MACRO(sym,val)  { val },
struct tipostruct nomearray []=
{
#include "pippo.def"
};
---
in questo modo quando devi modificare qualche cosa modifichi solo
"pippo.def" e l'array reale e l'header saranno sempre allineati.
ciao
ilmira

 "pippo.def" e l'array reale e l'header saranno sempre allineati.
Spettacolo!
Era proprio quello che cercavo...
Una curiosità. Perchè #undef MACRO? Solo per sicurezza?

 Una curiosità. Perchè #undef MACRO? Solo per sicurezza?
nel  .c e' necessario in quanto sicuramente hai incluso l'header
corrisopndente e quindi c'e' gia' la definizione di MACRO, nell'header e'
solo per sicurezza.
ciao
ilmira

 solo per sicurezza.
Ho appena provato e funziona egregiamente quando la struttura è
formata soltanto da un campo.
Se definisco una struttura formata da più campi, quando definisco
MACRO devo prevedere la sfilza dei parametri:
  #define MACRO( sym, valore_campo1, valore_campo2, ...,
valore_campon) sym,
oppure
  #define MACRO( sym, valore_campo1, valore_campo2, ...,
valore_campon) { valore_campo1, valore_campo2, ... valore_campon },
Oltre ad essere fastidioso da scrivere e brutto da leggere
(soprattutto se la struttura è formata da più campi), ho spostato il
problema a rendere coerente la definizione della struttura e la
definizione delle due MACRO (se aggiungo un campo, devo aggiungerlo
anche nelle #define del .c e del .h). Certo è un problema di minore
importanza rispetto a quello originale, poichè la definizione della
struttura cambia meno spesso rispetto ai record.
Magari esiste una soluzione a questo problema?

 Magari esiste una soluzione a questo problema?
non credo.
se devi aggiungere un campo che deve anch'esso avere una inizializzazione e'
ovvio che i dati contenuti in "pippo.def" devono essere tutti coerenti con
la nuova struttura.
quindi le due definizioni di MACRO le dovrai cambiare in accordo (sono solo
2, non e' tanto oneroso farlo) alla nuova struttura.
al massimo, ma secondo me e' brutto e poco chiaro da leggere, puoi
aggiungere i nuovi campi, sempre come ultimo o primo parametro di MACRO nel
file "pippo.def" ma poi il nuovo campo puo' essere in una posizione
qualsiasi della struttura, ossia non e' necessario che l'ordine dei
parametri di MACRO sia uguale all'ordine dei campi della struttura, la
definizione di MACRO fatta nel .c si occupera' di mettere i valori nel
giusto ordine.
se invece i nuovi campi aggiunti non vanno inizializzati, ti basta
aggiungerli al fondo della struttura, e MACRO continuera' a funzionare senza
dover essere aggoirnata.
ciao
ilmira