Gab*_*iel 5 c runtime initialization
我并不是真正的C设计模式,所以我的疑问可能很简单(虽然有点具体).这个问题的真正应用难以解释,所以让我简化一下.
假设我有一个数组,我想在其中存储素数.此数组包含的素数的数量由NUMBER_OF_PRIMES在编译时定义的常量定义.
因此,我们有:
unsigned primes[NUMBER_OF_PRIMES];
Run Code Online (Sandbox Code Playgroud)
如果大小是固定的,我可以预先计算素数并像往常一样初始化数组:
unsigned primes[NUMBER_OF_PRIMES] = { 2, 3, 5, 7, ... };
Run Code Online (Sandbox Code Playgroud)
但是,如果这将是相当丑陋的NUMBER_OF_PRIMES人,比方说,大于200我想一些方法来运行在运行时的功能,但在此之前的main(),这将把那些素数号码出现.我当然可以这样做:
unsigned* primes = make_primes(NUMBER_OF_PRIMES);
Run Code Online (Sandbox Code Playgroud)
这将分配必要的内存并在main之前运行.主要问题是:此数组将位于头文件中,但它的值将包含隐藏在相应.c文件中的内容.我认为我能做的是:
/* Header file */
unsigned primes[NUMBER_OF_PRIMES];
/* C file */
int nothing = initialize_primes(); /* This function would write the
values to the array, using things that are not available in the
header (it is in the .c, so it can reference them), and return anything */
Run Code Online (Sandbox Code Playgroud)
另一种方法显然是放入initialize_primes()头文件,并要求用户在main函数内调用它(就像一些库的init()函数).但是,我不想强制main()包含对此函数的调用.
我的问题是,如果有任何优雅的方式来做到这一点是公认/使用,或者如果这是荒谬的,我应该问main()打电话的init()功能,以避免不必要的,晦涩难懂的代码.
正如我所说,我没有处理与素数相关的任何事情; 这只是一个同样挑战的例子.
最好的祝福.
使用init函数是正确的方法.不要忘记添加一个fini函数,这样人们可以释放内存(如果他们想要的话)(不知道你的库有什么可能或者可能不重要但通常能够释放所有内存是好的 - 例如当一个库由可加载模块使用时,它通常不希望在卸载时泄漏内存.
为什么以前需要它运行main?我能想到的唯一原因是你不能控制main(即,你只是一个有人会打电话的图书馆).
在这种情况下,坚持让调用者调用您的初始化函数是完全可以的.API在他们的代码与您的代码之间形成合同,如果他们违反合同,则不是您的责任.
如果您进行控制,main那么只需在开始时调用您自己的初始化功能.它并不需要任何早期发生.
如果你决定走下来的静态数组路线,你不希望在所有的素数输入(如你的状态,他们是不是素数,但我猜想他们是可计算的),那么你可以写一个单独的程序作为构建工具的一部分(未随程序部署).
它可以根据该常量预先计算值,并使用您可以编译和链接的数组创建一个C文件.这至少可以消除打字输入的苦差事.
这也会使计算成本远离用户,从而加快启动速度(假设成本非常重要).
你可以做的一个技巧是:
// primes.c
static unsigned *p = NULL;
const unsigned *primes(void)
{
if(p == NULL)
{
p = malloc((PRIMES_COUNT + 1) * sizeof *p);
*p++ = 0; // if user accidentally frees p now, it will segfault
// populate p
atexit(primes_cleanup);
}
return p;
}
void primes_cleanup(void)
{
if(p)
{
free(p - 1); // correct way to free the pointer
p = NULL; // now calling _cleanup twice is fine
}
}
Run Code Online (Sandbox Code Playgroud)
用户使用primes()[N]获取所需元素,并保证初始化.即使您存储指针并在以后使用它,它也能保证正常工作(除非有人const在你不看的时候抛弃并更改了你的清单).如果您仍想要类似于变量的语法,请使用以下命令:
// primes.h
const unsigned *primes(void);
void primes_cleanup(void);
#define PRIMES (primes())
Run Code Online (Sandbox Code Playgroud)
对于最终用户,PRIMES将看起来像任何其他变量.赢得.