Можно ли в программе на C сбросить все глобальные переменные в значения по умолчанию? - PullRequest
3 голосов
/ 14 сентября 2010

У меня есть старое C Linux-приложение, которое мне нужно повторно использовать. Это приложение использует много глобальных переменных. Я хочу повторно использовать основной метод этого приложения и вызывать его в цикле. Я обнаружил, что когда я вызываю основной метод (переименованный в callableMain) в цикле, поведение приложения не согласовано, так как значения глобальных переменных, заданные в предыдущей итерации, влияют на ход программы в новой итерации.

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

например, оригинальная программа выглядит так

OriginalMain.C

#include <stdio.h>

int global = 3; /* This is the global variable. */

void doSomething(){     
         global++; /* Reference to global variable in a function. */    
}    

     // i want to rename this main method to callableMain() and
     // invoke  it in a loop 
     int main(void){    
       if(global==3) {    
       printf(" All  Is Well \n");    

       doSomething() ;  
     }
     else{

       printf(" Noooo\n");  

       doNothing() ;

     }
     return 0;
}

Я хочу изменить эту программу следующим образом:

Я изменил вышеуказанный файл, чтобы переименовать main () в callableMain ()

И мои новые основные методы таковы:

int main(){  

     for(int i=0;i<20;i++){  

         callableMain();

         // this is where I need to reset the value of global vaiables
        // otherwise the execution flow  changes
     }    
}   

Возможно ли сбросить все глобальные переменные к значениям до вызова main ()?

Краткий ответ: нет магического вызова API, который бы сбрасывал глобальные переменные. Глобальные переменные должны быть кэшированы и использованы повторно.

Ответы [ 7 ]

8 голосов
/ 14 сентября 2010

Я бы вызвал его как подпроцесс, изменяя его ввод и вывод по мере необходимости.Пусть операционная система сделает всю грязную работу за вас.

Идея состоит в том, чтобы изолировать устаревшую программу от вашей новой программы, передав ее в свой собственный процесс.Тогда у вас будет чистое разделение между ними.Кроме того, устаревшая программа сбрасывается в чистое состояние при каждом запуске.

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

Затем можно создать именованные каналы (используя вызов mkfifo) и вызвать унаследованную программу, используя system, передав ей именованные каналы вкомандная строка.Затем вы передаете ему свои данные и читаете их результаты.

Я не эксперт по этим вопросам;вероятно, есть лучший способ сделать IPC.Другие здесь упоминали fork.Однако основная идея выделения унаследованного кода и вызова его в качестве подпроцесса, вероятно, является лучшим подходом здесь.

5 голосов
/ 14 сентября 2010

fork () рано?

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

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

Более простой вариант может состоять в том, чтобы просто изменить код, чтобы процесс мог запускаться в «рабочем режиме», а затем использовать fork() или system(), чтобы запустить приложение сверху, но с аргументом, который помещает это в подчиненном режиме.

3 голосов
/ 14 сентября 2010

Есть способ сделать это на определенных платформах / компиляторах, вы в основном выполняете ту же инициализацию, которую выполняет ваш компилятор перед вызовом main().

Я сделал это для TI DSP, в этом случае у меня был раздел с глобальными переменными, сопоставленными с определенным разделом памяти, и были доступны директивы компоновщика, которые объявили переменные, указывающие на начало и конец этого раздела (так что memset() вся область обнуляется перед началом инициализации). Затем компилятор предоставил список записей, каждая из которых состояла из адреса, длины данных и фактических данных, которые должны быть скопированы в местоположение адреса. Таким образом, вы просто просматриваете записи и вводите memcpy() в целевой адрес, чтобы инициализировать все глобальные переменные.

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

1 голос
/ 14 сентября 2010

Короче, нет. В этом случае я бы создал определения, константы, если хотите, и затем использовал их для сброса глобальных переменных с помощью.

В основном

#define var1 10
int vara = 10

и т. Д. ... основной C, верно? Затем вы можете пойти и обернуть повторную инициализацию в удобную функцию =)

0 голосов
/ 14 сентября 2010

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

0 голосов
/ 14 сентября 2010
for (int i = 0; i < 20; i++) {
    int saved_var1 = global_var1;
    char saved_var2 = global_var2;
    double saved_var3 = global_var3;

    callableMain();

    global_var1 = saved_var1;
    global_var2 = saved_var2;
    global_var3 = saved_var2;
}

Или, может быть, вы можете узнать, где глобальные переменные начинаются memcpy их. Но я всегда съеживался, когда начинал цикл ...

for (int i = 0; i < 20; i++) {
    static unsigned char global_copy[SIZEOFGLOBALDATA];
    memcpy(global_copy, STARTOFGLOBALDATA, SIZEOFGLOBALDATA);

    callableMain();

    memcpy(STARTOFGLOBALDATA, global_copy, SIZEOFGLOBALDATA);
}

0 голосов
/ 14 сентября 2010

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

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

РЕДАКТИРОВАТЬ:

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

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

void callableMain()
{
  static bool first_iter = true;

  if (first_iter)
  {  
    first_iter = false;
    static int my_global_var1 = global_var1;
    static float my_global_var2 = global_var2;
    ..
  }

  // perform operations on my_global_var1 and my_global_var2, 
  // which store the default values of the original global variables.

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...