代码之家  ›  专栏  ›  技术社区  ›  StoneThrow

在C语言中,有没有一种方法可以确保在没有pthread_的情况下只调用一次函数?

  •  0
  • StoneThrow  · 技术社区  · 6 年前
    < > 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() 如果它被调用一次,我对编译时保证感兴趣,<>代码>函数()>代码>仅是调用函数范围中的一个名为的,即类似于<代码> C++ ++ >代码>如何处理上面的代码。 (换言之,上述代码对于<代码> C++ 编译器是合法的,它确保<代码>函数()/代码>只被调用一次——在<代码> C <代码>中没有等效的方法来做到这一点吗?没有<代码> pthRead一次?

    编辑:
    我没有在原来的帖子中这样表述:我在寻找一个不涉及包装器/帮助器函数或变量的解决方案,即我很想知道在<代码> C < /C>语言> /e>中是否有一个 构造,允许这种情况等价地处理它在<代码> C++ 中如何处理。JXH的解决方案最适合这种情况,利用 gcc 延伸. < /P>

    3 回复  |  直到 6 年前
        1
  •  1
  •   jxh    6 年前

    无法利用静态变量初始化

    试图利用静态变量初始化将不起作用。C只允许 static 要用常量初始化的变量,因此将发出函数调用。

    程序启动(或库加载)时函数的一次性调用

    不清楚为什么要一次性调用,但是如果在程序启动时可以这样做,那么就有一个特定于gcc的解决方案。 您可以分配 constructor 该函数的属性。

    #include <stdio.h>
    
    __attribute__((constructor)) 
    void func()
    {
      puts(__func__);
    }
    
    int main () {}
    

    此建议不执行您的特定任务:

    < Buff行情>

    我对编译时保证func()只从调用函数作用域调用一次感兴趣…

    < /块引用>

    相反,它确保函数在程序启动时(或者当它所属的库被加载时)被精确地调用一次。

    使用静态变量作为保护

    如果需要以初始化函数局部静态变量的准确方式来控制何时调用函数,则可以使用静态变量来跟踪单次函数是否已使用自己的静态变量调用。其他答案已经描述了如何完成这一点,但为了完整性:

    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();
    }
    
        2
  •  2
  •   Ajay Brahmakshatriya    6 年前

    可以将函数包装在另一个函数中,该函数检查静态变量并调用 func 如果以前没有打过电话-

    static int func_internal() {
        ...
    }
    
    int func() {
        static int guard = 0;
        if (guard)
            return 0;
        guard = 1;
        return func();
    }
    
    

    现在,只向其他模块公开 func

        3
  •  1
  •   nwn    6 年前

    你可以用 static 旗.

    // main.c
    
    int func()
    {
      return 42;
    }
    
    int main( int argc, char* argv[] )
    {
        static int initialized = 0;
        if(!initialized) {
            func();
            initialized = 1;
        }
    }
    

    第一次通过呼叫码, initialized 标志未设置,因此函数将运行。对于任何后续调用,已设置标志,因此不会调用函数。