4

First of all, this is definitely about C, no C++ solutions are requested.

Target: Return to the caller function (A) beyond multiple stack frames.

I have some solutions, but none of them feels like the best option.

The easiest one in the sense of implementation is longjmp/setjmp, but I am not sure if it destroys auto variables, because as wiki refers, no normal stack unwinding taking part if longjmp is performed.

Here is a short description of the program flow: the A function calls file processing function, which results in many internal and recursive invocations. At some point, file reader meets EOF, so the job of file processing is done and control should be given to A function.

Comparing each read character against EOF or '\0'? No, thanks. UPD: I can avoid dynamic allocations in the call chain between setjmp and longjmp.

Not being sure about auto variables, I do not know what will happen in sequential calls to file processing (there is more than 1 file).

So:

1) Whats about 'no stack unwinding' by longjmp? How danger is that if I got all the data holders available (pointers).

2) Other neat and effective ways to go back to the A frame?

  • 1
    You'll have to avoid keeping state that needs cleanup on the stack, and register cleanup functions in such a way that the target of your longjmp can call them (not unlike what C++ does during exception handling ;-) – thebjorn Jan 02 '15 at 08:51
  • 1
    So, basically, you want exceptions in C because you do not want to do error checking at every level. In this case, stack unwinding is not your only concern. You'll have to be very careful of dynamically allocated memory and pointers that might get lost along the way. – SirDarius Jan 02 '15 at 08:57
  • As @thebjorn points you'll probably need to implement some structure to clean up particularly if you haven't opened all the files before `setjmp()` or (for example) allocate any memory during the execution. If it's a complex as you say you might find registering and unregistering those clean-ups is no easier then a more conventional model. It's not uncommon to find C programs that are 50% error handling particularly when dealing with file I/O. – Persixty Jan 02 '15 at 08:59
  • Be careful about using recursion on data whose size you don't know beforehand. You may end up with a stack overflow on some input files. – jmajnert Jan 02 '15 at 09:12

1 Answers1

3

I don't know what you read somewhere, but setjmp/longjmp is exactly the tool foreseen for the task.

longjmp re-establishes the "stack" exactly (well sort of) as it has been at the call to setjmp, all modifications to the "stack" that had been done between the two are lost, including all auto variables that have been defined. This re-establishment of the stack is brute forward, in C there is no concept of destructors, and this is perhaps meant by "no stack unwinding".

I put "stack" in quotes since this is not a term that the C standard applies, it only talks about state and allows that this is organized how it pleases to the implementation.

Now the only information that you are able to keep from the time between setjmp and longjmp are:

  • the value that you pass to longjmp
  • the value of modified volatile objects that you defined before setjmp

So in the branch where you come back from longjmp you have to use this (and only this) information to cleanup your mess: close files, free objects that you malloced etc.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Thanks for clarifying. But even if its a "tool foreseen for the task", quite hard to start use it after so many people "consider it dangerous". – Iskander Sharipov Jan 02 '15 at 09:43
  • @IskanderSharipov, sure, nobody said it would be easy :) The first question you should ask yourself is if it is worth it. Popping up from recursion after a long file processing should not make a noticeable difference in processing time. As for all these things, identify the real bottlenecks of your program before you go for such delicate optimizations. – Jens Gustedt Jan 02 '15 at 10:13