This is the talk page for discussing improvements to the Setjmp.h article. This is not a forum for general discussion of the article's subject. |
Article policies
|
Find sources: Google (books · news · scholar · free images · WP refs) · FENS · JSTOR · TWL |
This article is rated C-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||||||||||||
|
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)
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)
I removed a very verbose section of code, supposedly "...by pietro gagliardi; august 25, 2006" (152.163.100.7)
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)
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
The second code example has a few problems:
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?
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
!
operator with the resulting expression being the entire controlling expression of a selection or iteration statement; or(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)
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)
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.)
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); */ }
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)
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)
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)
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)
-- Nic Roets 19:09, 16 September 2007 (UTC)
...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.
"C99 provides that longjmp is guaranteed to work only when (...)" This is an ambiguous wording. I assume you meant to say something like "the only guarantee is that it works when (...)". However, the wording "is guaranteed to work only when(...)" rather suggests a meaning such as "it is guaranteed to fail otherwise". —Preceding unsigned comment added by 92.202.69.70 (talk) 10:12, 25 February 2009 (UTC)
The Single UNIX Specification, Version 4 from The Open Group:
: set jump point for a non-local goto – System Interfaces Reference,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)
A simpler example before the first one may be useful to smooth out the learning curve:
#include "stdio.h" #include "setjmp.h" jmp_buf jmpbuf; void func() { longjmp(jmpbuf, 1); } int main(void) { if (!setjmp(jmpbuf)) { puts("First time."); func(); } else puts("Second time."); return 0; }
Per this diff:
Potatoswatter, would you please explain the deletion of this material. You wrote in the edit summary that the issue was "already addressed". However, I do not see any material indicating that returning from the function which called setjmp will invalidate the jump buffer. Maybe I'm missing something. Before you delete the content again, would you please indicate where in the article this is explained? I am asking, because this is a fairly common error and, after a very lengthy debugging session due to this error, I think it would be useful for programmers if the Wikipedia article mentioned this limitation. Thank you for your time and for your consideration.
← Michael Safyan (talk) 00:45, 29 July 2008 (UTC)
C99 provides that longjmp is guaranteed to work only when the destination is a calling function, i.e., that the destination scope is guaranteed to be intact. Jumping to a function that has already terminated by return or longjmp is undefined.[6] However, most implementations of longjmp do not specifically destroy local variables when performing the jump. Since the context survives until its local variables are erased, it could actually be restored by setjmp. In many environments (such as Really Simple Threads and TinyTimbers), idioms such as if(!setjmp(child_env)) longjmp(caller_env); can allow a called function to effectively pause-and-resume at a setjmp.
Hi. The section on multitasking seems to imply that setjmp/longjmp can only be used for cooperative multitasking. However, I have implemented a user thread library with preemption based on setjmp/longjmp. I would be happy to provide the example as public domain on Wikipedia. My only concern about doing so is that the source may be too long for the article; the header "uthr.h" is roughly 80 lines and the source file "uthr.cpp" is roughly 1500 lines. The example uses sigaltstack to ensure that the threads run on separate stacks, so that if one of the stacks is overrun, it will not silently corrupt the stack of one of the other threads. For preemption, it uses the setitimer function; this could be replaced with SetTimer on Windows. Anyway, are there any thoughts on this? Here is the header file to give a small sample:
Comments? Thoughts? Thank you in advance for your responses. ← Michael Safyan (talk) 00:02, 31 July 2008 (UTC)
There appears to me to be a bug of sorts in the sample code under this heading. If second() were to hypothetically complete successfully and return, first() would then also return without restoring the exception stack. If some hypothetical later part of the program were to then raise an exception and longjmp() to exception_env, it would find exception_env still containing the environment of the now non-existent first(). Is there some additional subtlety I'm missing here? 203.171.85.67 (talk) 04:11, 18 July 2009 (UTC)
Reading over this, I get the impression that use of setjmp/longjmp is sort of considered like wanton use of goto (meaning goto used more than one single time as a well-defined and quick exit that can avoid having the visual nesting-nightmare that a do..while(0) construct can become..) Something that should almost never be done, in favor of "better" constructs in newer languages - the language-level support for exceptions in C++, call/cc in Scheme/LISP (?), explicit coroutine syntax in whatever languages use them, system-level threading and multi-tasking constructs, etc. Is this impression correct, that setjmp is basically how exceptions were implemented before C++ existed (and possibly how exceptions were implemented in C++ compilers)? If so, are there any circumstances where setjmp should be used in modern programming languages, other than embedded systems if using C++ would be prohibitive on a memory/processor/etc basis.Jimw338 (talk) 17:51, 21 April 2012 (UTC)
It's no secret that all three code examples are slightly messy. And I'm no expert on this whole editing Wikipedia thing kids these days do but after an attempt at cleanup by User:82.9.176.6 (Me), User:Schily reverted the change because apparently "int main(void) is wrong."
I'm not entirely sure how it is "wrong." Two other functions in that example (first() and second()) are already declared this way. This is common occurrence and is used all over the latest C99 Draft which this code is supposed to conform to.
I wanted to just revert this unwarranted revert but I expect it will just devolve to a war. Does anyone have anything wrong with reverting the change? I don't see anything wrong with the proposed code: https://en.wikipedia.org/w/index.php?title=Setjmp.h&oldid=668969362#Exception_handling
It compiles fine under gcc -std=c99 -pedantic -Wall -Wextra with no errors or warnings and the only warnings given by clang -std=c99 -pedantic -Weverything are regarding unreachable code and functions which should be noreturn. And also, I personally find it much cleaner.
Arch-TK (talk) 21:07, 26 July 2015 (UTC)
int main(void)
has been correct since C89 (I don't know of a PDF it would be legal to link to, sorry—but see C89 §2.1.2.2 a.k.a. C90 §5.1.2.2.1 if you can find a copy of either), so any implementation that disallows this is wrong and has been wrong for at least 26 years. Also, one of the code examples is preceded by the remark: "The following code adheres to the 1999 ISO C standard", so expecting it to be written in some sort of lowest-common-denominator dialect seems unreasonable.//
is supposed to demonstrate, but if you're saying C99 is broken and silly, this isn't the best evidence for it. Comments are deleted during tokenization (C89 §2.1.1.2, C90 §5.1.1.2, C99 §5.1.1.2), a translation phase traditionally handled by the preprocessor; other preprocessor features are (and always have been) sensitive to the kind of whitespace given:#define ok this is ok
#define bad this
isn't ok
char *c = "this is a correct string literal";
char *d = "this is a
syntax error";
{
int a = 2, b = 4;
int c = a+++b; /* 6 */
}
{
int a = 2, b = 4;
int c = a+/**/++b; /* 7 */
}
main
, and since prototypes were invented by the same standard that disallowed providing one for main
, I don't imagine they are very common. 86.163.139.100 (talk) 10:41, 27 July 2015 (UTC)
int a = 9; a //* comment */= 3;
A K&R cpp converts this into:
int a = 9; a /= 3;
Your example is based on the precedence of ++ before +. AFAIR: int main(void) is something that was introduced by C++ and not valid in C, but I'll check for a C89 standard and read. Schily (talk) 12:51, 27 July 2015 (UTC)
int main(void) {...}
or int main(int argc, char *argv[]) {...}
. Nothing more, nothing less. Additionally, main is also defined like this in example #7 at §7.8.1 C99 (or example #7 at §7.7 in C90).
Very nice article. However, could anyone explain why this stack cushion thing works or give some reference. It seems to me like plain magic. I don't know why it works. But it definitely does. (I googled it, but came up with just a lot of cushions) 188.146.129.53 (talk) 21:34, 29 November 2015 (UTC)
Hello fellow Wikipedians,
I have just modified one external link on Setjmp.h. Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:
When you have finished reviewing my changes, you may follow the instructions on the template below to fix any issues with the URLs.
This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template ((source check))
(last update: 5 June 2024).
Cheers.—InternetArchiveBot (Report bug) 16:36, 12 June 2017 (UTC)