我是否应该相信库初始化函数被调用以支持性能?

时间:2015-01-11 20:02:03

标签: c

我正在用C(而不是C ++)创建一个库,并对常见做法有疑问。

此库需要调用%libname%_Init()函数,以便其他函数可以执行其相应的职责(如果不是,则必然会发生未定义/意外行为,可能导致崩溃)。

如果用简单的if (%random_var%)调用它,我可以轻松检查每个函数的顶部,所以我想知道是否有一个约定。

Ps¹:一个真实的例子是SDL.h需要SDL_Init( /*modules to be initialized */ )

Ps²:如果stackoverflow不适合此类问题,我会道歉

1 个答案:

答案 0 :(得分:2)

如果您不介意利用gcc(以及其他可能的)扩展,您可以查看__attribute__ ((constructor))(参见here),它保证在{{{{}}之前立即调用函数。 1}}。这样就可以调用知道你的init函数了。

但是,在一般情况下,如果您的库需要初始化,那可能是错误的。您可能希望避免在库中使用全局变量,这意味着您不希望使用这种init函数。

作为一个陷入这个陷阱的伟大图书馆的一个例子,请看main()。它有一个你需要调用的init函数来分配内存。为了让任何人看到(例如)libxml2的干净输出,他们需要释放这个分配的内存,所以他们必须调用一个deinit函数;当然只有一些应用程序这样做。到现在为止还挺好。但是如果另一个库(libfoo)也使用valgrind会发生什么呢?他们都调用init函数(很棒)。但是谁有人称之为deinit功能呢?如果libfoo没有调用它,那么使用libfoo的任何东西都会泄漏内存。如果libfoo确实调用它,那么任何使用libfoo的东西在用libfoo完成后都不能使用libxml2。令人讨厌的混乱(作者承认)。

更好的策略是每个用户获取库的上下文(通过单个调用,返回指针),它分配一个libxml2,其中包含您原本用作全局变量的内容。该指针传递给每个调用。这样你知道 init函数必须被调用,因为这是获得这样一个指针的唯一方法。此外,如果每个上下文仅由一个线程使用,那么您的库几乎是自动线程安全的(显然您需要避免使用任何本身依赖于全局变量的函数)。一个例子:

struct