Idea is that you redefine macro X to make data fit your current purpose.
You need at least 2 files. First is a huge table with necessary information, and others where data is used.
table.x:
X("Human", 2, HUMAN)
X("Spider", 8, SPIDER)
module.c:
// ID constants
enum {
#define X(description, legs, id) id,
#include "table.x"
#undef X
COUNT // Last element is total number of elements
};
// Leg array
int NumberOfLegs [] = {
#define X(description, legs, id) legs,
#include "table.x"
#undef X
};
// Description array
const char * Descriptions [] = {
#define X(description, legs, id) description,
#include "table.x"
#undef X
};
Preprocessed output would be:
// ID constants
enum {
HUMAN,
SPIDER,
COUNT // Last element is total number of elements
};
// Leg array
int NumberOfLegs [] = {
2,
8,
};
// Description array
const char * Descriptions [] = {
"Human",
"Spider",
};
In the above example it is easy to add new items to tables. If you managed those lists separately, it would be more easier to make an error.
Edit:
Some clarification on macro usage.
In first line #define X(description, legs, id) legs,
we define X
macro. Macro must have same number of arguments as our table.x
has on each line. For this usage we are only interested on legs
parameter. Note that argument names are meaningless, we could as well do #define X(a, b, c) b,
.
Second line #include "table.x"
includes contents of table.x
to module.c
. Because macro X
has been defined, preprocessor does text replacement to each line with call to X
.
Third line #undef X
is only for convenience. We remove definition of X
so it can be redifined later without compiler throwing warnings.