[英]Is there a way, in C, to ensure a function is called only once without pthread_once?
在C
,是否有一种方法可以确保不使用pthread_once
而仅调用一次函数?
以这些工作为C++
,但显然不是在C
因为一个静态变量初始化必须是恒定的(因为我解释编译错误)
// main.c
int func()
{
return 42;
}
int main( int argc, char* argv[] )
{
static int i = func();
return 0;
}
我以为使用逗号运算符可能会解决此问题,但这也不起作用:
// main.c
int func()
{
return 42;
}
int main( int argc, char* argv[] )
{
static int i = ( func(), 42 );
return 0;
}
两者的编译都会导致以下编译错误:
> gcc -g main.c
main.c: In function 'main':
main.c:10:18: error: initializer element is not constant
有什么方法可以避免这种情况并确保一个函数仅在调用函数作用域中被调用一次而不使用pthread_once
?
具体来说,如果func()
一次被调用,我不想从func()
早返回 ,我对编译时的保证感兴趣,即func()
仅在调用函数作用域中被调用一次,即类似于C++
将处理上述代码。
(换句话说,上面的代码对于C++
编译器是合法的,可以确保func()
仅被调用一次-是否有等效的方法可以在C
使用pthread_once
来做到这一点?)
编辑:
我没有在最初的帖子中理想地表达这一点:我在寻找一种不涉及包装器/帮助器函数或变量的解决方案。 即我很好奇是否用C
语言构造了这种情况,就等同于用C++
处理了。 jxh的解决方案最适合使用gcc
扩展。
您尝试利用静态变量初始化将不起作用。 C仅允许使用常量初始化static
变量,因此无法进行函数调用。
目前尚不清楚为什么要进行一次性调用,但是如果可以在程序启动时进行一次调用,则可以使用特定于GCC的解决方案。 您可以将constructor
属性分配给该函数。
#include <stdio.h>
__attribute__((constructor))
void func()
{
puts(__func__);
}
int main () {}
该建议不执行您的特定要求:
我对编译时保证func()仅在调用函数作用域中被调用一次感兴趣...
相反,它确保在程序启动时(或在加载该库的一部分时)恰好调用一次该函数。
如果您需要控制何时以正确的方式初始化函数本地的静态变量的初始化,则可以使用静态变量来跟踪是否已使用自己的静态变量调用了一个shot函数。 其他答案已经描述了如何完成此操作,但出于完整性考虑:
void caller_of_func()
{
static bool func_already_called;
if (!func_already_called) {
func();
func_already_called = true;
}
/*...*/
}
实现目标的另一种方法是通过函数指针调用函数。 对该函数的初始调用将完成实际工作,然后将函数指针切换为指向不执行任何操作的函数。
void nothing_func(int *x);
void initial_func(int *x);
void (*func)(int *x) = initial_func;
void initial_func(int *x) {
*x = 42;
puts(__func__);
func = nothing_func;
}
void nothing_func(int *x) {
puts(__func__);
}
void foo(void) {
static int x;
func(&x);
printf("%s: %d\n", __func__, x);
++x;
}
int main(void) {
foo();
foo();
}
您可以将函数包装到另一个函数中,该函数将检查静态变量并仅在之前未调用过func
时才调用func
,例如-
static int func_internal() {
...
}
int func() {
static int guard = 0;
if (guard)
return 0;
guard = 1;
return func();
}
现在,仅将func
公开给其他模块。
您可以使用static
标志来执行此操作。
// main.c
int func()
{
return 42;
}
int main( int argc, char* argv[] )
{
static int initialized = 0;
if(!initialized) {
func();
initialized = 1;
}
}
第一次通过调用代码时,未设置initialized
标志,因此将运行该函数。 对于任何后续调用,该标志已经设置,因此将不会调用该函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.