не использовать функции перед инициализацией, подобные конструкторам в C - PullRequest
3 голосов
/ 14 июня 2010

Так я могу предотвратить использование funA, funB, funC и т. Д. Перед использованием init

#define INIT_KEY 0xC0DE //any number except 0, is ok

static int initialized=0;

int Init()
{
  //many init task
  initialized=INIT_KEY;
}


int funA()
{
 if (initialized!=INIT_KEY) return 1;
 //..
}

int funB()
{
 if (initialized!=INIT_KEY) return 1;
 //..
}

int funC()
{
 if (initialized!=INIT_KEY) return 1;
 //..
}

Проблема этого подхода заключается в том, что если некоторые из этих функций вызываются внутрицикл, так что "if (initialized! = INIT_KEY)" вызывается снова и снова, хотя это и не нужно.

Это хороший пример того, почему конструкторы полезны, ха-ха. Если бы это был объект, я был бы уверен, чтокогда он был создан, была вызвана инициализация, но в Си я не знаю, как это сделать.

Любые другие идеи приветствуются!

Ответы [ 5 ]

5 голосов
/ 15 июня 2010

Использовать указатель на функцию.

Во время построения укажите функции на функцию, которая выполняет требуемую инициализацию, затем обновите указатели на функции, чтобы они указывали на фактические функции, выполняющие эту работу.

Я сделал это с массивамиуказателя на функции-члены в классе.У класса есть внутреннее целое число, которое сообщает, в каком состоянии объект, в котором он находится. Целое число используется для индексации в массиве указателей на функции-члены ... Состояние 0 выполняет init.Состояние 1, делает работу, состояние 2 возвращает вещи в состояние 1.

Это работало очень чисто.

4 голосов
/ 15 июня 2010

Вы можете использовать некоторые утверждения, использующие некоторые макросы препроцессора:

#ifdef DEBUG
#  define ENSURE_INITIALIZED(obj) \
     do { \
         if (obj->initialized != INIT_CODE) { \
             fprintf (stderr, "Object %p not initliaized (%s:%d)\n", obj, __FILE__, __LINE__); \
             abort (); \
         } \
     } while (0)
#else
#  define ENSURE_INITIALIZED(obj)
#endif

voif foo (Object *obj) {
    ENSURE_INITIALIZED (obj);
}

Это будет проверять код инициализации, но только в отладочных сборках - в рабочих сборках оно будет оцениваться как неактивное.

Вызов abort приведет к аварийному завершению программы, обычно оставляя дамп ядра или прерывая программу при запуске в отладчике.

1 голос
/ 15 июня 2010

Решением было бы выполнить инициализацию следующим образом (в каждом файле):

static int initResult = Init();

Когда программа запустится, эти статические переменные будут автоматически инициализированы и будет вызвана функция.

ВАЖНОЕ ПРИМЕЧАНИЕ: Порядок инициализации не определен, если вам нужно выполнить такие инициализации в более чем одном файле (обычно порядок связывания объектов диктует порядок инициализации - но для этого нет правила ).Поэтому вы должны быть осторожны при этом.

1 голос
/ 15 июня 2010

Вы можете думать о различных решениях.В цикле, независимо от выбранного решения, всегда будет выполняться некоторый дополнительный код (в лучшем случае за кулисами), чтобы предотвратить выполнение функций.Вы можете пропустить выполнение цикла funX, но это будет дополнительный код, чтобы проверить, можно ли выполнить funX, расположив его по-другому.

Поскольку обычно инициализация выполняется перед другой задачей, это странная проблема, илинеправильное название (вы не должны называть его инициализацией).

Если хотите, функции могут вызывать инициализатор самостоятельно, например,

if (!initialized) initialize();

Всегда дополнительный код, и инициализированный! будетс этого момента всегда ложь.

Но способ избежать проверки снова и снова - это явно вызвать инициализацию в правильном месте, прежде чем игра начнет играть по-настоящему.(В противном случае не называйте это инициализацией).

Если бы это был объект, ... вам не нужен объект для этого.Чтобы «вызвать» конструктор, вы должны создать объект (по крайней мере, во многих языках ОО), скажем, с помощью new MyClass() или «объявив его»;здесь вызов «new» (это не вызов, но для этой речи мы можем думать так) или «объявление» заменяется вызовом явного инициализатора.Ваш, очевидно, простой

Object a;
// ...
a.method(); //or

Object *a = new Object();
// ...
a->method();

будет

init()
// ...
funA();

Даже если этот пример не «соответствует» вашей «потребности», он должен прояснить, что явный инициализатор не так уж плохи языки OO действительно не нужны, чтобы «исправить» эту проблему.

Вы можете контролировать, когда вы можете вызывать эти функции, так что вам вообще не нужна проверка;это происходит во многих библиотеках, которые требуют сначала вызова специальной функции инициализации, прежде чем вы сможете их использовать, или следует ожидать «странного» поведения.

1 голос
/ 15 июня 2010

Поместите свои функции в структуру (используйте указатели на функции для доступа к ним). Предоставьте функцию «конструкция» для создания этой структуры и назначьте правильные адреса функций в структуре. Почти такая же идея, как у EvilTeach.

...