Search code examples
cstatic-variablesvariable-initialization

Is there a way, in C, to ensure a function is called only once without pthread_once?


In C, is there a way to ensure a function is called only once without using pthread_once?

The following works in C++ but apparently not in C because initialization of a static variable must be to a constant (as I interpret the compile error)

// main.c

int func()
{
  return 42;
}

int main( int argc, char* argv[] )
{
  static int i = func();
  return 0;
}

I thought using the comma operator might get around this, but that doesn't work either:

// main.c

int func()
{
  return 42;
}

int main( int argc, char* argv[] )
{
  static int i = ( func(), 42 );
  return 0;
}

Compilation of both results in the following compile error:

> gcc -g main.c
main.c: In function 'main':
main.c:10:18: error: initializer element is not constant

Are there any ways to circumvent this and ensure a function is only invoked once (from a calling function scope) without using pthread_once?

To be specific, I don't want to return early from func() if it has been called once, I'm interested in compile-time assurance that func() is only called once from a calling function scope - i.e. similar to how C++ would handle the above code.
(In other words, the above code is legal to a C++ compiler, which ensures func() is only called once - is there an equivalent way to do this in C without pthread_once?)

EDIT:
I didn't phrase this ideally in the original post: I was looking for a solution that didn't involve wrapper/helper functions or variables; i.e. I was curious to know if there was a construct in the C language that allowed this situation to be handled equivalently to how it is handled in C++. jxh's solution fits that best, making use of a gcc extension.


Solution

  • No way to leverage static variable initialization

    Your attempt to leverage static variable initialization will not work. C only allows static variable to be initialized with constants, so a function call is out.

    One shot call of a function at program start (or library load)

    It is not clear why you want the onetime call, but if it's okay to do it at program startup, there is a GCC specific solution. You can assign the constructor attribute to the function.

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

    This suggestion does not perform your specific ask:

    I'm interested in compile-time assurance that func() is only called once from a calling function scope ...

    Instead, it assures the function is called exactly once when the program starts (or when the library it is a part of is loaded).

    Use a static variable as a guard

    If you need to control when the function is called in the exact way initialization of a static variable local to a function is initialized, then you could use a static variable to track whether your one shot function has been called yet with its own static variable. Other answers have already described how to accomplish this, but for completeness:

    void caller_of_func()
    {
        static bool func_already_called;
        if (!func_already_called) {
            func();
            func_already_called = true;
        }
        /*...*/
    }
    

    Use a function pointer!

    Another way to accomplish your goal would be to call the function through a function pointer. The initial call to the function would do the real work, and then switch the function pointer to point to a function that does nothing.

    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();
    }