I am not an expert C programmer and I know that including .c
source file from another is considered bad practice, but I have a situation where I think it could help maintainability.
I have a big structure with a lot of elements and I use #define
to keep the indexes.
#define TOTO_IND 0
#define TITI_IND 1
…
#define TATA_IND 50
static const MyElements elems [] = {
{"TOTO", 18, "French"},
{"TITI", 27, "English"},
...,
{"TATA", 45, "Spanish"}
}
Since I need to access the structure from index, I need to keep the #define
and the structure declaration synchronized. That means that I must insert new elements at the right place and update the #define
accordingly.
It is error prone and I don’t really like it (but for performance consideration, I didn’t find a better solution).
Anyway, this file also contains a lot of functions to handle this structure. I also want to keep separation of code and avoid global variables.
To make things “easier”, I was thinking about moving this “error prone definition” to a single .c
source file which would only contain this structure. This file would be “the dangerous be careful file” and include it in my actual “normal functional” file.
What do you think about it? Is it a valid situation for including .c
source file? Is there another better way of handling my structure?
You should use designated initializers as shown in the answer by Ian Abbot.
Additionally, if the array indices are adjacent as seems to be the case here, you can use an enum instead:
toto.h
typedef enum
{
TOTO_IND,
TITI_IND,
...
TATA_IND,
TOTO_N // this is not a data item but the number of items in the enum
} toto_t;
toto.c
const MyElements elems [] = {
[TITI_IND] = {"TITI", 27, "English"},
[TATA_IND] = {"TATA", 45, "Spanish"},
[TOTO_IND] = {"TOTO", 18, "French"},
};
And now you can verify the data integrity of the array as whole with a static assert:
_Static_assert(sizeof elems/sizeof *elems == TOTO_N,
"Mismatch between toto_t and elems is causing rain in Africa");
_Static_assert(sizeof elems/sizeof *elems == TOTO_N, ERR_MSG);
where ERR_MSG
is defined as
#define STR(x) STR2(x)
#define STR2(x) #x
#define ERR_MSG "Mismatching toto_t. Holding on line " STR(__LINE__)