Talk:Setjmp.h

From Wikipedia, the free encyclopedia

This article is supported by the Wikipedia:WikiProject C++. Please visit the project page for more details on the project.

Contents

[edit] copyvio

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)

[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)

[edit] Suggested change in default case

Does anyone mind if the default code is changed to:

    default: {
            /* Take any action required on failure. */
            printf("first failed, status %d\n", specific_status);
            break;

The default case is wrong when specific_status is 0, since it says status is nonzero. Nereocystis 21:08, 17 January 2007 (UTC)

Yes, but specific_status is only 0 when setjmp returns a non-zero value that is not caught by a case label. I've changed it to:
       default: {
           /* Take any action required on failure. */
           if (specific_status != 0)
             printf("first failed, status %d\n", specific_status);
           else
             printf("first failed, status unknown\n");
           break;
       }

Hopefully that's clearer. –EdC 21:53, 17 January 2007 (UTC)

[edit] Cooperative multitasking

I just removed the section titled "Cooperative multitasking", which contained a program purporting to use setjmp and longjmp to simulate two threads running concurrently. Unfortunately, that's not the way longjmp works — you can't "longjmp" to a place (such as the middle of child) that no longer exists. longjmp is similar to C++ exception handling: you can jump around inside a single function, or you can "unwind the stack" to an earlier position, but you can't jump "down" the stack, from main to child, and expect anything sensible to happen.

The code may very well work on some implementations, but given that this is an encyclopedia article on the standard C header, which is shared by all implementations, it doesn't make sense to include platform-specific code here. --Quuxplusone 02:11, 15 September 2007 (UTC)

Something doesn't have to be supported on all platforms in order to be mentioned in an encyclopedia like Wikipedia. A majority or a significant number will do esp. if it's clearly documented
I've tested this code on Cygwin before posting and my research has shown that this technique is used widely in thread libraries like Really Simple Threads and TinyTimbers. Please list any architechtures on which you know it doesn't work before you say it's platform-specific.
Perhaps you know of a specification or recommendation that says setjmp cannot be used to jump "down" the stack, but then you refer to it in the section I added instead of deleting it.

-- Nic Roets 19:09, 16 September 2007 (UTC)

ISO/IEC 9899:1999 7.13.2.1:2:

...if the function containing the invocation of the setjmp macro has terminated execution211) in the interim, or if the invocation of the setjmp macro was within the scope of an identifier with variably modified type and execution has left that scope in the interim, the behavior is undefined.

Still, if this mechanism is used it should be mentioned. EdC 19:23, 16 September 2007 (UTC)
'Anonymous' removed references to C99 and his comment hinted that it's also 'undefined' under C89 and 'probably also K&R'. So he implied that it's not only undefined according to standards documents, but also to most implementations of setjmp. It works under most implementaions. —Preceding unsigned comment added by Nroets (talkcontribs) 15:33, 20 September 2007 (UTC)

[edit] Just plain wrong, redux

setjmp: set jump point for a non-local goto – System Interfaces Reference, The Single UNIX® Specification, Issue 6 from The Open Group:

      An application shall ensure that an invocation of setjmp() appears in one of the
      following contexts only:
       * The entire controlling expression of a selection or iteration statement
       * One operand of a relational or equality operator with the other operand an
         integral 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
       * The entire expression of an expression statement (possibly cast to void)
      If the invocation appears in any other context, the behavior is undefined.

Taking the return of setjmp is undefined behaviour. It may work on your platform, but it is not portable. EdC (talk) 01:59, 14 April 2008 (UTC)