Talk:Setjmp.h

From Wikipedia, the free encyclopedia

I've written a new article, using a non-tainted para from the previous version: Talk:Setjmp/longjmp/Temp. EdC 19:36, 16 July 2006 (UTC)

I have moved that to be the main version. Mangojuicetalk 11:35, 29 July 2006 (UTC)

What is this copyvio all about? Isn't one GFDL project allowed to use information from another GFDL project ??? 209.92.136.131 19:25, 17 July 2006 (UTC)

Not if the copied text has invariant sections and cover text that the including project is unable to respect. EdC 00:59, 18 July 2006 (UTC)

Contents

[edit] Just Plain Wrong

I removed a very verbose section of code, supposedly "...by pietro gagliardi; august 25, 2006" (152.163.100.7)

  1. Segfaults on the scanf.
  2. Does not do what the comments say it does

While I could rewrite this code, it's much clearer to just use User:BrianCully's since it exhibits the behavior of setjmp/longjmp in less lines. (I'll test that next, but I have a feeling it's much higher quality code.) krallja 06:50, 27 August 2006 (UTC)

OK, I realized that User:BrianCully's version doesn't exhibit nonlocal flow control, so I wrote one that basically did what "pietro" was trying to do, except without the pointer mistakes. krallja 07:09, 27 August 2006 (UTC)

[edit] Re: Just Plain Wrong

Sorry, didn't see that. I thought, when I wrote the code, that it was to demonstrate exactly how setjmp/longjmp worked with deeply nested function calls (in my case, up to 4 levels) - pietro gagliardi, october 1, 2006

[edit] The second code example could be better

The second code example has a few problems:

  • The "while" would be better as "if", since it's not actually controlling the iteration; "i" is set outside the "loop" each time.
  • It prints that longjmp will be called with i, but actually it is called with i + 1.
  • It doesn't demonstrate the value being passed from longjmp to setjmp very well.
  • It shouldn't give the impression that this is an ok way to iterate. Perhaps a big comment about "for demonstration only, don't actually do this."

I'd be happy to just delete this second exanple.

  Please leave it there. That is the simplest way to explain what setjmp/longjmp do.

An example of the fork-like idiom mentioned in the first paragraph of the article would be much better. It would demonstrate not only what setjmp/longjmp does, but why you might want to use it, and give an effective example of how to use setjmp/longjmp in your own code.

The code in the second example still doesn't do what it says it does. If it's so confusing that people editing this article haven't gotten it right after a couple of tries, what are people reading this article in order to learn about setjmp/longjmp going to think?

[edit] Speaking of just plain wrong...

What do other editors think — is it worth reworking all three examples to be proper ANSI C? At the moment, every one of them invokes undefined behavior because the setjmp invocations are not

  • the entire controlling expression of a selection or iteration statement;
  • one operand of a relational or equality operator with the other operand an integer constant expression, with the resulting expression being the entire controlling expression of a selection or iteration statement;
  • the operand of a unary ! operator with the resulting expression being the entire controlling expression of a selection or iteration statement; or
  • the entire expression of an expression statement (possibly cast to void).

(Quoted from N869.) The fix, of course, would be to rework each example to use switch (setjmp(jmp_buf)) ..., which might be less clear to the layman. I'll make the change in a few days if nobody objects, or points out another interpretation of the Standard on this issue. --Quuxplusone 06:47, 25 November 2006 (UTC)

No, you're absolutely right; it's one of those lesser-known gotchas. Actually, if you write a para about that issue in the article then that should help explain why the if(setjmp... or switch(setjmp... idiom is used. EdC 11:28, 25 November 2006 (UTC)

Okay, it's done. I added a quote and link to the C99 Rationale, too. I'm going to try to write up an example equivalent to "nested catch blocks" and add it to the page, but if it turns out to be too ugly, I won't add it. I already uglified the first example a little bit with that switch-statement fallthrough, but I wanted to get the idea of catching a specific return value and catching any non-zero return value indiscriminately. --Quuxplusone 19:57, 26 November 2006 (UTC)

[edit] Nested catch blocks

I'm putting this example here rather than in the article because it's so horribly hackish. Most importantly, I realized after writing the above comment that there's no way to "re-throw" an arbitrary status from first back to main; the nested function has to "declare" each of the exception types it might re-throw, which I've done with the RETHROW(value) macro. N.B.: the memcpy calls are virtually guaranteed to do the right thing, because jmp_buf is "an array type suitable for holding the information needed to restore a calling environment". (Still, that doesn't mean it does hold all the information needed to restore the environment — it could be an array[1] of pointers to records that really hold the data. But that would just be evil.)

If anyone can come up with a library (not original research :) that uses setjmp this way, I think that would be a valuable addition to the article. --Quuxplusone 00:55, 27 November 2006 (UTC)
#include <setjmp.h>
#include <stdio.h>
#include <string.h>

static jmp_buf global_jmpbuf;


#define THROW(value)    longjmp(global_jmpbuf, value)
#define TRY             do { jmp_buf tmp; \
                        memcpy(tmp, global_jmpbuf, sizeof tmp); \
                        switch (setjmp(global_jmpbuf)) { case 0:
#define CATCH(value)    break; case value:
#define RETHROW(value)  break; case value: \
                        memcpy(global_jmpbuf, tmp, sizeof tmp); \
                        THROW(value);
#define ENDTRY          break; } \
                        memcpy(global_jmpbuf, tmp, sizeof tmp); } while (0)

void first(void);
void second(void);

int main()
{
    TRY {
        first();
        puts("Returned to main.");
    } CATCH(1) {
        puts("Caught 1 in main");
    } ENDTRY;
    return 0;
}

void first(void)
{
    TRY {
        second();
    } CATCH(2) {
        puts("Caught 2 in first");
    } RETHROW(1) ENDTRY;
    return;
}

void second(void)
{
    THROW(1);
 /* THROW(2); */
}

[edit] merge with setjmp.h

Yes, I was too lazy to do it myself, so I just called attention to setjmp.h by adding a little bit of info. Go ahead with merge. Fresheneesz 06:06, 30 November 2006 (UTC)