<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://arolstar52-zhtest.hf.space/index.php?action=history&amp;feed=atom&amp;title=Setjmp.h</id>
	<title>Setjmp.h - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://arolstar52-zhtest.hf.space/index.php?action=history&amp;feed=atom&amp;title=Setjmp.h"/>
	<link rel="alternate" type="text/html" href="https://arolstar52-zhtest.hf.space/index.php?title=Setjmp.h&amp;action=history"/>
	<updated>2026-07-11T17:11:09Z</updated>
	<subtitle>在这个wiki上该页的修订历史</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://arolstar52-zhtest.hf.space/index.php?title=Setjmp.h&amp;diff=801390&amp;oldid=prev</id>
		<title>imported&gt;Mhss：​/* 告诫与限制 */</title>
		<link rel="alternate" type="text/html" href="https://arolstar52-zhtest.hf.space/index.php?title=Setjmp.h&amp;diff=801390&amp;oldid=prev"/>
		<updated>2025-12-15T06:08:10Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;告诫与限制&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{noteTA&lt;br /&gt;
|G1=IT&lt;br /&gt;
}}&lt;br /&gt;
{{C_Standard_library}} &amp;lt;!-- to edit this template go to [[template:C_Standard_library]] --&amp;gt;&lt;br /&gt;
{{lowercase|title=setjmp.h}}&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;setjmp.h&amp;#039;&amp;#039;&amp;#039;是[[C标准函数库]]中提供“非本地跳转”的[[头文件]]：[[控制流]]偏离了通常的子程序调用与返回序列。互补的两个函数setjmp与longjmp提供了这种功能。&lt;br /&gt;
 &lt;br /&gt;
setjmp/longjmp的典型用途是[[例外处理 (编程)|异常处理]]机制的实现：利用longjmp恢复程序或线程的状态，甚至可以跳过栈中多层的函数调用。&lt;br /&gt;
&lt;br /&gt;
==成员函数==&lt;br /&gt;
&lt;br /&gt;
{| class = wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;int setjmp(jmp_buf&amp;amp;nbsp;env)&amp;lt;/code&amp;gt; || 建立本地的&amp;lt;code&amp;gt;jmp_buf&amp;lt;/code&amp;gt;缓冲区并且初始化，用于将来跳转回此处。这个子程序&amp;lt;ref name=&amp;quot;macro&amp;quot;&amp;gt;ISO C标准要求&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;必须是宏实现，但POSIX明确称未定义&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;是宏实现还是函数实现。&amp;lt;/ref&amp;gt; 保存程序的调用环境于&amp;lt;code&amp;gt;env&amp;lt;/code&amp;gt;参数所指的缓冲区，&amp;lt;code&amp;gt;env&amp;lt;/code&amp;gt;将被&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;使用。如果是从&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;直接调用返回，&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;返回值为0。如果是从&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;恢复的程序调用环境返回，&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;返回非零值。&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;void longjmp(jmp_buf&amp;amp;nbsp;env, int&amp;amp;nbsp;value)&amp;lt;/code&amp;gt; || 恢复&amp;lt;code&amp;gt;env&amp;lt;/code&amp;gt;所指的缓冲区中的程序调用环境上下文，&amp;lt;code&amp;gt;env&amp;lt;/code&amp;gt;所指缓冲区的内容是由&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;子程序&amp;lt;ref name=&amp;quot;macro&amp;quot;/&amp;gt;调用所保存。&amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;的值从&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;传递给&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;。&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;完成后，程序从对应的&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;调用处继续执行，如同&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;调用刚刚完成。如果&amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;传递给&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;零值，&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;的返回值为1；否则，&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;的返回值为&amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt;。&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;保存当前的环境（即程序的状态）到平台相关的一个数据结构 (&amp;lt;code&amp;gt;jmp_buf&amp;lt;/code&amp;gt;)，该数据结构在随后程序执行的某一点可被 &amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;用于恢复程序的状态到&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;调用所保存到&amp;lt;code&amp;gt;jmp_buf&amp;lt;/code&amp;gt;时的原样。这一过程可以认为是&amp;quot;跳转&amp;quot;回&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;所保存的程序执行状态。&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;的返回值指出控制是正常到达该点还是通过调用&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;恢复到该点。因此有编程的惯用法: &amp;lt;code&amp;gt;if( setjmp(x) ){/* handle longjmp(x) */}&amp;lt;/code&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
==成员类型==&lt;br /&gt;
&lt;br /&gt;
{| class = wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;jmp_buf&amp;lt;/code&amp;gt; || 数组类型，例如&amp;lt;code&amp;gt;struct int[16]&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;Visual Studio 2008用法&amp;lt;/ref&amp;gt;或&amp;lt;code&amp;gt;struct __jmp_buf_tag&amp;lt;/code&amp;gt;&amp;lt;ref&amp;gt;[[GNU C 函式庫]] 2.7的用法&amp;lt;/ref&amp;gt;，用于保存恢复调用环境所需的信息。&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==告诫与限制==&lt;br /&gt;
&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;实现了非本地跳转，微软的IA32程序设计环境中正常的&amp;quot;[[调用栈#栈解绕|栈解开]]&amp;quot;因而没有发生，所以诸如栈中已定义的局部变量的析构函数的调用（用于销毁该局部变量）都没有执行。所有依赖于栈解开调用析构函数所做的扫尾工作，如关闭文件、释放堆内存块等都没有做。但在微软的X64程序设计环境，&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;启动了正常的&amp;quot;栈解开&amp;quot;。&amp;lt;ref&amp;gt;Microsoft Visual C++ 2010 x32或x64与Intel ICC 2011 (version 12) x32或x64，编译结果都是&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;启动了正常的&amp;quot;栈解开&amp;quot;。但GCC 4.4 x32版编译的&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;不执行&amp;quot;栈解开&amp;quot;。可见，是否“栈解开”不具有移植性。&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
如果&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;所在的函数已经调用返回了，那么&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;使用该处&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;所填写的对应&amp;lt;code&amp;gt;jmp_buf&amp;lt;/code&amp;gt;缓冲区将不再有效。这是因为&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;所要返回的&amp;quot;栈帧&amp;quot;(stack frame)已经不再存在了，程序返回到一个不再存在的执行点，很可能覆盖或者弄坏程序栈.&amp;lt;ref&amp;gt;{{Cite web |url=http://www.cs.utk.edu/~mbeck/classes/cs560/360/notes/Setjmp/lecture.html |title=CS360 Lecture Notes — Setjmp and Longjmp |accessdate=2011-06-06 |archive-date=2010-07-04 |archive-url=https://web.archive.org/web/20100704192041/http://www.cs.utk.edu/~mbeck/classes/cs560/360/notes/Setjmp/lecture.html |dead-url=no }}&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;{{Cite web |url=http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=setjmp(3)&amp;amp;msection= |title=setjmp(3) |accessdate=2011-06-06 |archive-date=2009-07-26 |archive-url=https://web.archive.org/web/20090726081425/http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=setjmp%283%29&amp;amp;msection= |dead-url=no }}&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==使用例子==&lt;br /&gt;
===简单例子===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;setjmp.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
static jmp_buf buf;&lt;br /&gt;
&lt;br /&gt;
void second(void) {&lt;br /&gt;
    printf(&amp;quot;second\n&amp;quot;);         // 打印&lt;br /&gt;
    longjmp(buf,1);             // 跳回setjmp的调用处 - 使得setjmp返回值为1&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void first(void) {&lt;br /&gt;
    second();&lt;br /&gt;
    printf(&amp;quot;first\n&amp;quot;);          // 不可能执行到此行&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main() {   &lt;br /&gt;
    if ( ! setjmp(buf) ) {&lt;br /&gt;
        first();                // 进入此行前，setjmp返回0&lt;br /&gt;
    } else {                    // 当longjmp跳转回，setjmp返回1，因此进入此行&lt;br /&gt;
        printf(&amp;quot;main\n&amp;quot;);       // 打印&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
上述程序将输出: &lt;br /&gt;
 second&lt;br /&gt;
 main&lt;br /&gt;
注意到虽然&amp;lt;code&amp;gt;first()&amp;lt;/code&amp;gt;子程序被调用，&amp;quot;&amp;lt;code&amp;gt;first&amp;lt;/code&amp;gt;&amp;quot;不可能被打印。&amp;quot;&amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;&amp;quot;被打印，因为条件语句&amp;lt;code&amp;gt;if ( ! setjmp(buf) )&amp;lt;/code&amp;gt;被执行第二次。&lt;br /&gt;
&lt;br /&gt;
=== 异常处理 ===&lt;br /&gt;
在下例中，&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;被用于包住一个例外处理，类似[[例外处理 (编程)|&amp;lt;code&amp;gt;try&amp;lt;/code&amp;gt;]]。&amp;lt;code&amp;gt;longjmp&amp;lt;/code&amp;gt;调用类似于&amp;lt;code&amp;gt;throw&amp;lt;/code&amp;gt;语句，允许一个异常返回给&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;一个异常值。下属代码示例遵从[[C99|1999 ISO C standard]]与[[Single UNIX Specification]]：仅在特定范围内引用&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt;，&amp;lt;code&amp;gt;switch&amp;lt;/code&amp;gt;或它们的嵌套使用的条件表达式&lt;br /&gt;
*上述情况下与&amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt;一起使用或者与整数常值比较&lt;br /&gt;
*作为单独的语句(不使用其返回值)&lt;br /&gt;
遵从上述规则使得创建程序环境缓冲区更为容易。更一般的使用&amp;lt;code&amp;gt;setjmp&amp;lt;/code&amp;gt;可能引起[[未定义行为]]，如破坏局部变量；编译器被要求保护或警告这些用法。但轻微的复杂用法如&amp;lt;code&amp;gt;switch ((exception_type = setjmp(env))) { }&amp;lt;/code&amp;gt;在文献与实践中是常见的，并保持了相当的可移植性。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;setjmp.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
void first(void);&lt;br /&gt;
void second(void);&lt;br /&gt;
 &lt;br /&gt;
/* This program&amp;#039;s output is:&lt;br /&gt;
 &lt;br /&gt;
calling first&lt;br /&gt;
calling second&lt;br /&gt;
entering second&lt;br /&gt;
second failed with type 3 exception; remapping to type 1.&lt;br /&gt;
first failed, exception type 1&lt;br /&gt;
 &lt;br /&gt;
*/&lt;br /&gt;
 &lt;br /&gt;
/* Use a file scoped static variable for the exception stack so we can access&lt;br /&gt;
 * it anywhere within this translation unit. */&lt;br /&gt;
static jmp_buf exception_env;&lt;br /&gt;
static int exception_type;&lt;br /&gt;
 &lt;br /&gt;
int main() {&lt;br /&gt;
    void *volatile mem_buffer;&lt;br /&gt;
 &lt;br /&gt;
    mem_buffer = NULL;&lt;br /&gt;
    if (setjmp(exception_env)) {&lt;br /&gt;
        /* if we get here there was an exception */&lt;br /&gt;
        printf(&amp;quot;first failed, exception type %d\n&amp;quot;, exception_type);&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Run code that may signal failure via longjmp. */&lt;br /&gt;
        printf(&amp;quot;calling first\n&amp;quot;);&lt;br /&gt;
        first();&lt;br /&gt;
        mem_buffer = malloc(300); /* allocate a resource */&lt;br /&gt;
        printf(&amp;quot;%s&amp;quot;,strcpy((char*) mem_buffer, &amp;quot;first succeeded!&amp;quot;)); /* ... this will not happen */&lt;br /&gt;
    }&lt;br /&gt;
    if (mem_buffer)&lt;br /&gt;
        free((void*) mem_buffer); /* carefully deallocate resource */&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void first(void) {&lt;br /&gt;
    jmp_buf my_env;&lt;br /&gt;
 &lt;br /&gt;
    printf(&amp;quot;calling second\n&amp;quot;);&lt;br /&gt;
    memcpy(my_env, exception_env, sizeof(jmp_buf));&lt;br /&gt;
    switch (setjmp(exception_env)) {&lt;br /&gt;
        case 3:&lt;br /&gt;
            /* if we get here there was an exception. */&lt;br /&gt;
            printf(&amp;quot;second failed with type 3 exception; remapping to type 1.\n&amp;quot;);&lt;br /&gt;
            exception_type = 1;&lt;br /&gt;
&lt;br /&gt;
        default: /* fall through */&lt;br /&gt;
            memcpy(exception_env, my_env, sizeof(jmp_buf)); /* restore exception stack */&lt;br /&gt;
            longjmp(exception_env, exception_type); /* continue handling the exception */&lt;br /&gt;
&lt;br /&gt;
        case 0:&lt;br /&gt;
            /* normal, desired operation */&lt;br /&gt;
            second();&lt;br /&gt;
            printf(&amp;quot;second succeeded\n&amp;quot;);  /* not reached */&lt;br /&gt;
    }&lt;br /&gt;
    memcpy(exception_env, my_env, sizeof(jmp_buf)); /* restore exception stack */&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void second(void) {&lt;br /&gt;
    printf(&amp;quot;entering second\n&amp;quot; ); /* reached */&lt;br /&gt;
    exception_type = 3;&lt;br /&gt;
    longjmp(exception_env, exception_type); /* declare that the program has failed */&lt;br /&gt;
    printf(&amp;quot;leaving second\n&amp;quot;); /* not reached */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==用于信号处理==&lt;br /&gt;
在[[Signal.h|信号处理机制]]中，进程在检查收到的信号，会从原来的系统调用中直接返回，而不是等到该调用完成。这种进程突然改变其上下文的情况，就是通过使用setjmp和longjmp来实现的。setjmp将保存的上下文载入用户空间，并继续在旧的上下文中继续执行。这就是说，进程执行一个系统调用，当因为资源或其他原因要去睡眠时，内核为进程作了一次setjmp，如果在睡眠中被信号唤醒，进程不能再进入睡眠时，内核为进程调用longjmp，该操作是内核为进程将现在的上下文切换成原先通过setjmp调用保存在进程用户区的上下文，这样就使得进程可以恢复等待资源前的状态，而且内核为setjmp返回1，使得进程知道该次系统调用失败。&lt;br /&gt;
&lt;br /&gt;
==参考文献==&lt;br /&gt;
{{reflist}}&lt;br /&gt;
&lt;br /&gt;
==外部链接==&lt;br /&gt;
* [http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html Exceptions in C with Longjmp and Setjmp]{{Wayback|url=http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html |date=20110615175107 }}&lt;br /&gt;
&lt;br /&gt;
[[Category:C标准库头文件]]&lt;br /&gt;
[[category:控制流程]]&lt;/div&gt;</summary>
		<author><name>imported&gt;Mhss</name></author>
	</entry>
</feed>