One approach which I've used when programming an embedded system where memory was somewhat tight was to use some macros to both define a structure type and define its initial value. The definition looked something like:
#define CREATE_FOO_STRUCT \
X(int age, 34) Y \
X(int height, 65) Y \
X(char const * favoritecolor,"blue") Y \
X(int some_things[5],ARR5(1,2,3,4,5))
The ARR5
macro was needed to allow the initialization values for that array to be passed as a single parameter; an alternative would have been to write the last line as X(int some_things[5],{1 COMMA 2 COMMA 3 COMMA 4 COMMA5})
. Given a macro like the above, it is possible to define X
and Y
so X
returns expands to first item and Y
to semicolon, in which case typedef {CREATE_FOO_STRUCT} FOO;
will define structure FOO
, and then redefine X
and Y
so that X
returns the second item and Y
a comma, in which case const FOO default_FOO = {CREATE_FOO_STRUCT};
will define a default instance. It's too bad I don't know any way to avoid the need to have either the last line differ from the others (the last line could match the others if each line but the first was preceded by X
, and if the last line was followed by a //this line must be left blank
line.
On the particular processor where I implemented the above constructs, defining default_FOO
in that way would consume zero RAM, and consume ROM equal to the size of default_FOO
. A function which would load a static instance of FOO
with the default values, using conventional assignment statement, would consume four bytes of ROM for each non-zero byte in default_FOO
, and would also require that there be a static instance it could use. A C-language function which would accept a FOO*
and load the pointed-to instance with default values would take a monstrous amount of code (each assignment would have to separately compute the address of the data to be stored).