2013-10-31 35 views
2

我想静态初始化一个结构,该结构将在包含某个头文件的所有文件中可见。C:使用外部链接初始化全局常量

实际意图是运行在编译时指定的函数列表,这就是为什么我要静态初始化的原因。我想将它们所属的列表放在它们被声明或定义的文件中。

人为的例子:

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); ... } 

这显然是行不通的,因为“初始化剂元素不是常量” - 这是因为当编译器在翻译bar.c,它认为它不知道foo_widgets(或bar_widgets)的位置。

但由于bar.c#包括了foo.h无论如何,它总是编译旁边的foo.c:

gcc foo.c baz.c bar.c

所以我希望有一个在源代码中反映这一点的方式。

我不能在foo.h中声明foo_widgets,因为那样我将无法多次初始化它(因为foo.h包含在多个文件中)。

不雅的解决办法

了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()); ... } 

有没有更好的办法?

回答

2

你想有一个全局变量,你可以到达任何地方......为此,你必须声明它为外部变量在适当的头。

在这里,它应该做如下:

foo.h中:

/* ... */ 
int oof1(void); 
int oof2(void); 
extern int (*foo_widget)(void)[2]; 

在foo.c的:

int (*foo_widget)(void)[2] = {{oof1}, {oof2}}; 

通过这样做,当包括“foo。H”时,foo_widget变量将是已知的(并且预计定义别的地方 - 在这里的foo.c - )

为了更准确... 任何一段代码需要使用。的foo_widget必须有行extern int (*foo_widget)(void)[2];的地方,是它包含的头(更聪明的方式),或只是一个线在.C文件的开头。

当然,如果你不能提前知道电话号码您可能需要的小部件,您可能需要动态数据结构,例如链接列表或树(如果可能,请订购和平衡;))以存储他们。 extern变量可能是在需要时动态分配的常规指针。但定义行是仍需要,所以在这种情况下,您可能在适当的源文件中有类似struct my_struct *pointer = NULL;的东西。

注:我自由地用一个公共函数指针替换你的struct Widget,以使初始化更简单。

+0

谢谢:-)没有意识到你需要指定声明和定义的数组大小。 该结构对于存储与每个函数关联的附加数据是必需的。 – user234461

+0

@ user234461当然初始化可以为结构成员完成,它只是更多_“有些烦人”_,我留给你;) – Rerito