Как сбросить статические переменные внутри функции - PullRequest
7 голосов
/ 15 августа 2010

Есть ли способ сбросить переменные, объявленные как статические внутри функции? Цель состоит в том, чтобы убедиться, что функция не вызывается с длительными значениями из несвязанного вызова. Например, у меня есть функция, работающая над столбцами матрицы.

int foo(matrix *A, int colnum, int rownum){
static int whichColumn;
static int *v; //vector of length A->nrows 
   if (column != whichColumn){
    memset(v,0,size);
    whichColumn = which;
   } 
   //do other things
}

Функция вызывается n раз, один раз для каждого столбца. Это правильный способ «переустановки» статической переменной? Существуют ли другие общие надежные способы сброса статических переменных? Например, я хочу убедиться, что если вызов выполняется с новой матрицей, возможно, с другими размерами, то вектор v изменяется и обнуляется и т. Д. Кажется, самый простой способ - вызвать функцию с указателем NULL:

int foo(matrix *A, int colnum, int rownum){
static int whichColumn;
static int *v; //vector of length A->nrows 
   if (A == NULL){
    FREE(v);
    whichColumn = 0;
   } 
   //do other things
}

Ответы [ 5 ]

3 голосов
/ 15 августа 2010

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

Например:

int foo;
int *m = NULL;

static void InitVars() {
    foo = 0;
    if (m != NULL) {
        free(m);
    }
    m = malloc(sizeof(int)*5);
    memset(m, 0, sizeof(int)*5);
}

Если ваш инициализатор действительно идемпотентен, вы можете вызвать его снова для сброса переменных.

Если вам нужно , чтобы это вызывалось автоматически, используйте __attribute__((constructor)) (для GCC), например, так:

static void InitVars __attribute__((constructor)) ();

Однако вы должны заметить, что если вам нужно сделатьэто, вы должны пересмотреть использование переменных static внутри функции и вместо этого использовать переданные свежие переменные, которые возвращаются / записываются и передаются последующим связанным вызовам.

0 голосов
/ 28 февраля 2017

вы можете построить свою функцию таким образом, чтобы, если вы вызывали ее с нулевыми параметрами, она сбрасывала свои внутренние статические переменные

вот пример:

int foo(matrix *A = NULL, int colnum = 0, int rownum = 0)
{
   static int whichColumn;
   static int *v; //vector of length A->nrows 

   if (A == NULL){
    FREE(v);
    whichColumn = 0;
   } 
   //do other things
}

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

foo();  // internal values would then be reset

Убедитесь, что все ваши параметры функции имеют значения по умолчанию, если, например, вы передаете необязательный параметр, то убедитесь, что он имеет = boost :: none в качестве значения по умолчанию

0 голосов
/ 19 января 2012

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

extern unsigned long global_reset_count;

void do_something(int whatever)
{
  static ... this, that, the other, etc. ...;
  static unsigned long my_reset_count;

  if (my_reset_count != global_reset_count)
  {
    my_reset_count = global_reset_count;
    ... initialize this, that, the other, etc ...
  }  
}

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

Кроме того, альтернативный шаблон, который может быть полезен во встроенных системах, мог бы иметь глобальную переменную modules_initialized, которая устанавливается равной 0 с помощью метода глобального сброса, а затем каждый модуль должен начинаться с чего-то вроде:

  if (!atomic_bit_test_and_set32(&modules_initialized, FOOBOZZ_MODULE_ID))
  {
    ... Initialize module FOOBOZZ ...
  }

Это потребует, чтобы не было более 32 идентификаторов модулей, и потребовало бы, чтобы они были как-то уникально распределены, но некоторые системы могут справиться с этим довольно хорошо. Например, компоновщик может позволить определить «секцию данных» из адреса 0-31 адресного пространства, независимого от любого другого; если каждый модуль объявляет однобайтовую переменную в этом адресном пространстве, компоновщик может сгенерировать соответствующие адреса для этих переменных.

0 голосов
/ 15 августа 2010

Один из подходов, который я видел, использовался, когда модуль C был импортирован в C ++, заключался в том, чтобы окружить весь модуль оболочкой класса и заменить все статические переменные внутри функций уникальными именами «глобальных» переменных вне функций. Я не знаю ни одного хорошего способа добиться подобного эффекта для проектов, включающих несколько исходных файлов, хотя я хотел бы знать, существует ли такой. У меня есть некоторый встроенный системный код на C, который я моделирую, добавляя некоторые обертки C ++ в VS2005. Например, у меня есть регистры ввода / вывода, определенные так, чтобы что-то вроде TX1CON = 0x5C; будет переводиться в нечто вроде IOMAP (0x251) .P = 0x5C; IOMAP - это свойство, которое отправляет «запись 0x5C по адресу 0x251» в программу аппаратного моделирования. Этот подход работает хорошо, но я не могу сделать чистый сброс. Есть идеи?

0 голосов
/ 15 августа 2010

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

...