tags:

views:

131

answers:

6

I have a function f( ) in a file func.c and functions f1( ), f2( ), f3() , f4( ) in another file funcs.h. (Assume that all the functions receive/return values without any loss of generality).

  1. Function f( ) calls f4( )
  2. f4( ) calls f1( ), f2( ), f3( ) in some arbitrary order, among themselves
  3. At some point of time during the execution, f3() detects the completion of the algorithm and it has to "terminate" the execution of the algorithm. In a standalone case, it should exit out of the program after printing the solutions.But here, I need f3( ) to return to f( ).

This is my solution:

In this scenario, I cannot simply return to f4() (the original function called by f(), since there is already a function call stack of f1(), f2(), f3(),f4(), waiting to be "popped"). So, what I did is:

  1. I did a setjmp( ) in f() before calling f4( )
  2. And then, I did a longjmp( ) in f3( ) when I detected the completion of the algorithm

My question is: Is this the correct way to achieve this in this scenario?

+4  A: 

TBH I personally find its better to return a bool from the function and if the return is true then return true from the function below and so on until it gets back to the original function. This unwinds the stack correctly, which im not sure setjmp/longjmp does.

In general though if you aren't going to go on and do stuff after the f() function returns it should work anyway. I'd just argue its not a very good way to do things as someone reading the code will not find it as obvious as the functions returning bool back up the stack.

Goz
Returning `bool`s would be my solution too. If you want to return additional values, pass in a pointer argument to the place where the value should be stored.
Thomas
Thanks for the hint regarding "bool". Right now, it works, but I might be running into a "stack overflow" in other cases. I will try to recode my algorithm to make use of this and see if it helps.
Amit
A: 

f4( ) calls f1( ), f2( ), f3( ) in some arbitrary order, among themselves

What do you mean by "arbitrary order"? Unless you're writing a multi-threaded program, the order in which 1,2, and 3 are called should be deterministic; functions are executed synchronously in C.

Amber
I think that f3() might have something like:if ( someCondition ) { f3(something);else { f2(something);}
Macarse
By arbitrary order, I meant that the sequence of call/return was deterministic at runtime.
Amit
A: 

You didn't mention what you are doing or what algorithm are you implementing but...

You could use a global structure with function pointers which f1,f2,f3,f4 knows it existence and from f4() you call f1() doing something like:

global.functionPointers[0]("parameters.for.f1");
Macarse
A: 

Don't you still need a flag to know that you shouldn't call f4 again the second time?

int solution_found=0;

f(){
  setjmp();
  if (!solution_found)
    f4();
  /* continue here... */
}

Apart from that, setjmp/longjmp may be expensive calls. They also have a price in terms of readability of your program. I would certainly consider having f1,... pop themselves out of the stack the normal way instead, if I was you.

Pascal Cuoq
I will definitely need to call f4() again a second time, but for the next iteration of my overall code. I think I will need to invest some more time to the design of funcs.h to see if I could pop them out the normal way.
Amit
+1  A: 

You can use getcontext/setcontext. They may be viewed as an advanced version of setjmp/longjmp; whereas the latter allows only a single non-local jump up the stack, setcontext allows the creation of multiple cooperative threads of control, each with its own stack.

Also refer to other related calls such as makecontext(), swapcontext().
Here is one sample code to show how to use these functions (Sorry for bad coding). Hope this helps you.

    #include <stdio.h>
    #include <ucontext.h>

    void func(void);

    int  x = 0;
    ucontext_t context, *cp = &context;

    int main(void) {

      getcontext(cp);
      if (!x) {
        printf("getcontext has been called\n");
        func();
      }
      else {
        printf("setcontext has been called\n");
      }

    }

    void func(void) {

      x++;
      setcontext(cp);

    }

  Output:

  getcontext has been called    
  setcontext has been called
vinit dhatrak
Thanks for the pointer. Even if it doesn't help me here, will be good to know.
Amit
how? it is same as that of setjmp/longjmp. Do getcontext before f() calls f4(), then in f3(), after completion just do setcontext. It will return back to f(). Correct me if I have not understood your requirement.
vinit dhatrak
@Vinit- Why would I use setcontext/getcontext here instead of my setjmp/longjmp ?
Amit
getcontext/setcontext can be viewed as an advanced version of setjmp/longjmp; whereas the latter allows only a single non-local jump up the stack, setcontext allows the creation of multiple cooperative threads of control, each with its own stack. Please refer to man page of the same.
vinit dhatrak
A: 

I would do it something like this:

struct solution { ... }

solution *f() {
    solution *result;
    if (something) {
        result = f3();
        if (result != NULL)
            return result;
    }
    else {
        result = f3();
        if (result != NULL)
            return result;
    }
    return f();
}

Or whatever your algorithm might be.

erikkallen