tags:

views:

155

answers:

10

I got a function in a file that works for a single function call. But since it depends on alot of static declarations within this file (I didn't make this file, and its to big to modify). It wont work with multiple function calls.

Is there some way to make each function call unaware of previous calls, or current calls? In effect force a new address space for each functioncall.

like

//file inner.c
#include <stdio.h>

static int counter =1;

int incIt(int a){
  counter += a;
  return counter;
};

and the main file

//file outer.c
#include <stdio.h>
#include "inner.h"

int main(){
  fprintf(stderr,"first: %d\n",incIt(5));
  fprintf(stderr,"second: %d\n",incIt(7));  //this should be independent of previous calls.
  return 0;
}

compile like

gcc -c inner.c
gcc outer.c

thanks

A: 

You could try loading and unloading the object compiled from inner.c with dlopen.

altie
+3  A: 

You force a new address space by making all variables local (i.e. by giving them automatic storage duration). That's the whole purpose of automatic variables - each call gets its own independent set of local variables.

By declaring your variable static you are moving in opposite direction - you are explicitly requesting the compiler to use the same variable in each call. So, decide what it is you are trying to do and then do it.

If you can't modify the variable and/or function declarations, then you are out of luck. It can't be done.

AndreyT
+3  A: 

If you want the code to be reentrant, you have to avoid using global variables or file static variables.

In C++, you wrap the variables in a class (with a constructor), and instantiate the class for each separate set of operations.

In C, you simulate what you would do in C++.

For the example, in C++:

#include <stdio.h>
class Counter
{
    int counter;
public:
    Counter() : counter(1) { }
    int incIt(int a) { counter += a; return counter; }
};

int main()
{
    Counter c1;
    Counter c2;
    printf("First: %d\n", c1.incIt(5));
    printf("Second: %d\n", c2.incIt(7));
    return 0;
}

Or, in C:

#include <stdio.h>
typedef struct Counter
{
    int counter;
} Counter;

void initCounter(Counter *c) { c->counter = 1; }
int incIt(Counter *c, int a) { c->counter += a; return c->counter; }


int main()
{
    Counter c1;
    Counter c2;
    initCounter(&c1);
    initCounter(&c2);
    printf("First: %d\n", incIt(&c1, 5));
    printf("Second: %d\n", incIt(&c2, 7));
    return 0;
}

If you really can't change the source code, then you are stuck. One possibility is to extract the code you need into a new source file that allows for the reentrant design (with functions and variables renamed as necessary). Use the new code. Failing that, you are stuck - you have to go back to the supplier and plead for the necessary changes to be made.

Jonathan Leffler
+2  A: 

Fork a new child process for each call.

Jukka Suomela
+2  A: 

The simplest solution to the problem you present in the code is to add a new function to handle resetting the counter.

Obviously this does little to make the code re-entrant, but might be just what you need to clear past history.

Andrei
A: 

Here is the answer I would give if a coworker asked me that:

Don't do that!

ninjalj
A: 

"I'd like to change the world, but they just won't give me the sources"

  #define static 

for those declared in functions, and manually the rest of them from the global scope. It just doesn't mean that it will still work as expected.

ruslik
A: 

With the given requirements I offer this portable solution. The solution will mimic local variables. Replace all types encountered in static or global variables by a template class instantiated with with replaced type. The template class will store a stack of the replaced type. Arrange things so you can push and pop of this stack of all instances of this template class with a single call to push or pop. Upon entering your legacy function push, upon leaving pop.

The solution is not super-easy to implement but should allow the existing structure to stay as convoluted as it seems to be without resorting to nonportable ways like forking or dynamic loading.

Still, I think it's worthwile to take a step back and reconsider if the old code should not be rewritten anyway to save you from future pain.

Peter G.
+3  A: 

This statement "Is there some way to make each function call unaware of previous calls, or current calls?" Implies that this might work for you:

int incIt(int a){
  int localCounter = 1;
  localCounter += a;
  return localCounter;
};
Mark B
A: 

Ugly hack warning: Get a pointer to the first static/global in memory, and a pointer to the last. Write a wrapper function that copies the block of statics around so that each call gets it's own set of statics/globals. This assumes all the interesting statics/globals are contiguous in memory... The right solution is 'change the code like Jonathan Leffler describes'.

jsl4tv