Есть ли способ, в C, чтобы гарантировать, что функция вызывается только один раз без 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() вызывается только один раз из области вызывающей функции - то есть, как C++будет обрабатывать вышеуказанный код.
(Другими словами, приведенный выше код является законным для C++ компилятор, который обеспечиваетfunc()вызывается только один раз - есть ли эквивалентный способ сделать это в C без pthread_once?)

РЕДАКТИРОВАТЬ:
Я не формулировал это идеально в оригинальном посте: я искал решение, которое не включало бы функции-обертки / вспомогательные функции или переменные; то есть мне было любопытно узнать, была ликонструкция вCязык, который позволял обрабатывать эту ситуацию эквивалентно тому, как она обрабатывается в C++, Решение JXH подходит лучше всего, используя gcc расширение.

3 ответа

Решение

Нет способа использовать инициализацию статической переменной

Ваша попытка использовать инициализацию статической переменной не будет работать. С позволяет только static переменная для инициализации с помощью констант, поэтому вызов функции отсутствует.

Вызов функции одним выстрелом при запуске программы (или загрузка библиотеки)

Непонятно, зачем вам нужен одноразовый вызов, но если это нормально делать при запуске программы, есть специальное решение для GCC. Вы можете назначить constructor приписать функции.

#include <stdio.h>

__attribute__((constructor)) 
void func()
{
  puts(__func__);
}

int main () {}

Это предложение не выполняет ваш конкретный запрос:

Меня интересует гарантия времени компиляции, что 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();
}

Вы можете заключить вашу функцию в другую функцию, которая проверяет статическую переменную и вызывает 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 флаг не установлен, поэтому функция будет запущена. Для любых последующих вызовов флаг уже установлен, и поэтому функция не будет вызываться.

Другие вопросы по тегам