Reputation: 1205
I want to statically initialise a struct that will be visible from all files which include some header.
The actual intention is to run lists of functions specified at compile time, which is why I want to initialise statically. I'd like to put the lists where they belong, in the file in which they are declared or defined.
Contrived example:
general.h:
struct Widget { int (*a)(); };
foo.h:
int oof1(void);
int oof2(void);
foo.c:
#include "foo.h"
int oof1(void) { return 1; }
int oof2(void) { return 2; }
struct Widget foo_widgets[] = { {oof1}, {oof2} };
bar.c:
#include "foo.h"
#include "baz.h"
struct Widget *foo_widgets;
struct Widget *baz_widgets;
struct WidgetsContainer {
struct Widget *widget_list;
} wlists[] =
{
{ foo_widgets },
{ baz_widgets }
};
void usage(void) { ... ; process (wlists[i].widget_list); ... }
This obviously doesn't work because "the initialiser element is not constant" - This is because when the compiler is translating bar.c, it thinks it doesn't know the location of foo_widgets (or bar_widgets).
But since bar.c #includes foo.h anyway, it's always compiled alongside foo.c:
gcc foo.c baz.c bar.c
So I'm hoping there's a way of reflecting this in the source code.
I can't declare foo_widgets
in foo.h, because then I wouldn't be able to initialise it without defining it multiple times (as foo.h is included in more than one file).
Inelegant workaround
foo.h:
...
Widget *get_foos(void) { return foo_widgets; }
bar.c:
...
struct Widget_lists {
struct Widget (*widget_list)();
} wlist[] =
{
{ get_foos },
{ get_bazes }
};
void usage(void) { ...; process(wlist[i].widget_list()); ... }
Is there a better way?
Upvotes: 2
Views: 106
Reputation: 6086
You want to have a global variable that you can reach anywhere ... To do so you have to declare it as an external variable in the appropriate header.
Here, it should be done as follows :
In foo.h :
/* ... */
int oof1(void);
int oof2(void);
extern int (*foo_widget)(void)[2];
In foo.c :
int (*foo_widget)(void)[2] = {{oof1}, {oof2}};
By doing so, when including "foo.h", the foo_widget
variable will be known (and expected to be defined somewhere else - in foo.c here - ).
To be more precise ... Any piece of code that needs to make use of foo_widget
must have the line extern int (*foo_widget)(void)[2];
somewhere, be it in an included header (the smarter way) or just a line at the beginning of the .c file.
Of course, if you cannot know in advance the number of widgets you can have, you are likely to need a dynamic data structure such as a linked list or a tree (ordered and balanced if possible ;) ) to store them. The extern
variable is likely to be a regular pointer dynamically allocated when needed. But the definition line is still needed, so in this case you might have something like struct my_struct *pointer = NULL;
in the appropriate source file.
Note : I took the freedom to replace your struct Widget
with a common function pointer to get the initialization simpler.
Upvotes: 2