在C中模仿静态对象的构造函数

Posted

技术标签:

【中文标题】在C中模仿静态对象的构造函数【英文标题】:Imitating constructor of static objects in C 【发布时间】:2011-10-21 11:33:13 【问题描述】:

我想要一个全局的names 变量,看起来像这样

char* names[NAMES_CAP];
int names_len = 0;

我希望每个链接到这个库的人都能够向这个列表添加一个项目。

main 很容易做到这一点。

int main(int argc,char**argv) 
    names[names_len++] = "new name";
    names[names_len++] = "new name 2";

但是如果我想堆叠两个库怎么办? (即,我的库,libnames 保存全局变量。如果有人链接到使用libnameslibnameuser,它会自动将libnameuser 中定义的所有名称添加到libnames 中的names 数组中。

有什么办法吗?

在 C++ 中,我可以将 names[names_len++] = "..." 插入到全局对象的构造函数中,并且必须调用它。但是我可以用普通的 C 来做到这一点吗?

【问题讨论】:

【参考方案1】:

如果你使用 gcc,你可以使用构造函数属性__attribute__((constructor)) 来获得相同的效果。然而,这是非标准的 C。

但是我建议不要使用这种模式,因为在 main 之前运行的任何函数的顺序都无法控制。在 main 开始运行后,我宁愿找到一种很好的方法来挂钩所有“构造函数”。

【讨论】:

我不介意顺序。我会很高兴听到实现类似目标的更好模式。我想尽可能地让用户感到轻松。【参考方案2】:

更新:有关此答案的更新版本,请参阅 https://***.com/a/2390626/270788。

下面是一个预处理器抽象,用于支持 GCC 和 MSVC 的 C 静态初始化函数。 GCC 版本也适用于 LLVM CC,也许其他一些编译器也是如此。

MSVC 版本的工作原理是将静态初始化函数的 ptr 放置在由应用程序或 DLL 启动代码处理的特殊部分中。

#if defined(__GNUC__)
  #define INITIALIZER(f) \
    static void f(void) __attribute__((constructor)); \
    static void f(void)
#elif defined(_MSC_VER)
  #define INITIALIZER(f) \
    static void __cdecl f(void); \
    __declspec(allocate(".CRT$XCU")) void (__cdecl*f##_)(void) = f; \
    static void __cdecl f(void)
#endif

INITIALIZER(initializer_1)  names[names_len++] = "new name"; 
INITIALIZER(initializer_2)  names[names_len++] = "new name 2"; 

【讨论】:

请参阅***.com/a/2390626/270788 了解此答案的更新版本。【参考方案3】:

如果您不是 100% 关心可移植性并且可以保证 GCC,那么您可以使用 GCC 中的“构造函数”属性来做您想做的事情。见:http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Function-Attributes.html

不过,我同意@Anders K 的观点,他说您应该将这种行为封装在函数中。

【讨论】:

【参考方案4】:

我认为为了实现您想要的效果,最好为您的 names[] 数组创建几个包装函数。然后访问您的“全局”名称数组的模块必须通过该接口。

这将允许您更好地控制和解耦

然后您可以将数组放在一个模块中,然后在标题中公开这些函数,但保持数组隐藏。

【讨论】:

但问题仍然存在:如何从库代码中自动执行这些函数? @MagnusHoff 说了什么。我的问题不是阻止访问names,而是强制用户在访问我的库之前更新names【参考方案5】:

我认为全局变量的初始化也适用于 C。

int func1();
int someGlobalVariable = func1();

int func1()

    /* Your initialization code can go here */
 

我希望我没有误会这在 C 中工作(很长时间以来一直只使用 C++)。

【讨论】:

以上是关于在C中模仿静态对象的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

C ++中的静态构造函数?我需要初始化私有静态对象

c#中对象初始化是啥意思?

C++ - 全局静态对象和局部静态对象的构造函数调用不同?

请教一下C#中父类静态构造函数在子类中为啥不会和子类的静态构造函数一起执行

控制静态对象构造函数的顺序

C# 静态类构造函数