views:

289

answers:

7

I have a legacy C Linux application that I need to reuse . This application uses a lot of global variables. I want to reuse this application's main method and invoke that in a loop. I have found that when I call the main method( renamed to callableMain) in a loop , the application behavior is not consistent as the values of global variables set in previous iteration impact the program flow in the new iteration.

What I would like to do is to reset all the global variables to the default value before the execution of the the new iteration.

for example , the original program is like this

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

I want to change this program as follows:

I changed the above file to rename the main() to callableMain()

And my new main methods is as follows:

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
     }    
}   

Is this possible to reset all the global variables to the values before main() was invoked ?

The short answer is that there is no magical api call that would reset global variables. The global variables would have to be cached and reused.

+7  A: 

I would invoke it as a subprocess, modifying its input and output as needed. Let the operating system do the dirty work for you.

The idea is to isolate the legacy program from your new program by relegating it to its own process. Then you have a clean separation between the two. Also, the legacy program is reset to a clean state every time you run it.

First, modify the program so that it reads the input data from a file, and writes its output in a machine-readable format to another file, with the files being given on the command line.

You can then create named pipes (using the mkfifo call) and invoke the legacy program using system, passing it the named pipes on the command line. Then you feed it its input and read back its output.

I am not an expert on these matters; there is probably a better way of doing the IPC. Others here have mentioned fork. However, the basic idea of separating out the legacy code and invoking it as a subprocess is probably the best approach here.

David M.
This sounds promising. I was looking to use a OS level API cal to do the job for me. Would you be able to elaborate a bit more on your approach ?
See the edited answer.
David M.
A: 

I think you must change the way you see the problem.

Declare all the variables used by callableMain() inside callableMain()'s body, so they are not global anymore and are destroyed after the function is executed and created once again with the default values when you call callableMain() on the next iteration.

EDIT:

Ok, here's what you could do if you have the source code for callableMain(): in the beginning of the function, add a check to verify if its the first time the function its being called. Inside this check you will copy the values of all global variables used to another set of static variables (name them as you like). Then, on the function's body replace all occurences of the global variables by the static variables you created.

This way you will preserve the initial values of all the global variables and use them on every iteration of callableMain(). Does it makes sense to you?

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.

}
karlphillip
This is not feasible, as the global variables are being accessed by different function in different modules. Doing so causes too many compiler errors.
If the variables are no longer global, they will not be accessible by functions outside of callableMain() such as the doSomething() function in the question.
semaj
He doesn't want to rewrite this entire program; that's the point of the question.
David M.
Clever solution.
David M.
+1  A: 

In short, no. What I would do in this instance is create definitions, constants if you will, and then use those to reset the global variables with.

Basically

#define var1 10
int vara = 10

etc... basic C right? You can then go ahead and wrap the reinitialization in a handy function =)

Alex Hart
A: 
pmg
+2  A: 

There is a way to do this on certain platforms / compilers, you'd basically be performing the same initialization your compiler performs before calling main().

I have done this for a TI DSP, in that case I had the section with globals mapped to a specific section of memory and there were linker directives available that declared variables pointing to the start and end of this section (so you can memset() the whole area to zero before starting initialization). Then, the compiler provided a list of records, each of which comprised of an address, data length and the actual data to be copied into the address location. So you'd just loop through the records and do memcpy() into the target address to initialize all globals.

Very compiler specific, so hopefully the compiler you're using allows you to do something similar.

Praetorian
+1. Dangerous, but I <3 C.
quixoto
:-D Yes, dangerous indeed. But where's the fun in writing C if you're not living on the edge (especially in a bootloader project)!
Praetorian
A: 

If you don't want to refactor the code and encapsulate these global variables, I think the best you can do is define a reset function and then call it within the loop.

Shautieh
+5  A: 

fork() early?

You could fork(2) at some early point when you think the globals are in a good state, and then have the child wait on a pipe or something for some work to do. This would require writing any changed state or at least the results back to the parent process but would decouple your worker from your primary control process.

In fact, it might make sense to fork() at least twice, once to set up a worker controller and save the initialized (but not too initialized :-) global state, and then have this worker controller fork() again for each loop you need run.

A simpler variation might be to just modify the code so that the process can start in a "worker mode", and then use fork() or system() to start the application at the top, but with an argument that puts it in to the slave mode.

DigitalRoss
Or similarly, `exec`, if available and if you know how to identify the executable.
Steve Jessop
+1. I think that `fork` is preferable to `exec` here.
JSBangs