<!DOCTYPE html>
<html class="client-nojs vector-feature-language-in-header-enabled vector-feature-language-in-main-menu-disabled vector-feature-language-in-main-page-header-disabled vector-feature-page-tools-pinned-disabled vector-feature-toc-pinned-clientpref-0 vector-toc-not-available vector-feature-main-menu-pinned-disabled vector-feature-limited-width-clientpref-1 vector-feature-limited-width-content-enabled vector-feature-custom-font-size-clientpref-1 vector-feature-appearance-pinned-clientpref-0 skin-theme-clientpref-os vector-sticky-header-enabled skin-thumbsize-clientpref-standard" lang="zh" dir="ltr"><head>
    <meta charset="UTF-8">
    <title>Setjmp.h</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" type="image/png" href="./_res_/favicon.png">
    <link rel="canonical" href="https://zh.wikipedia.org/wiki/Setjmp.h"> <link href="./_mw_/ext.cite.styles.css" rel="stylesheet" type="text/css">
    <link href="./_mw_/ext.pygments.css" rel="stylesheet" type="text/css">
    <link href="./_mw_/ext.wikimediamessages.styles.css" rel="stylesheet" type="text/css">
    <link href="./_mw_/skins.vector.icons.css" rel="stylesheet" type="text/css">
    <link href="./_mw_/skins.vector.search.codex.styles.css" rel="stylesheet" type="text/css">
    <link href="./_mw_/skins.vector.styles.css" rel="stylesheet" type="text/css">
    <meta name="ResourceLoaderDynamicStyles" content="">
    <link href="./_mw_/ext.gadget.large-font.css" rel="stylesheet" type="text/css">
    <link href="./_mw_/ext.gadget.text-spacing.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" type="text/css" href="./_mw_/site.styles.css">
    <link rel="stylesheet" type="text/css" href="./_mw_/noscript.css">
    <link rel="stylesheet" type="text/css" href="./_res_/footer.css">
    <link rel="stylesheet" type="text/css" href="./_res_/vector-2022.css">
  </head>
  <body class="skin--responsive skin-vector skin-vector-search-vue mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject page-Setjmp_h rootpage-Setjmp_h skin-vector-2022 action-view">
    <div class="mw-page-container">
      <div class="mw-page-container-inner">
        <div class="mw-content-container">
          <main id="content" class="mw-body">
            <header class="mw-body-header vector-page-titlebar">
              <h1 id="firstHeading" class="firstHeading mw-first-heading">setjmp.h</h1>
            </header>
            <a id="top"></a>
            <div id="bodyContent" class="vector-body ve-init-mw-desktopArticleTarget-targetContainer" aria-labelledby="firstHeading" data-mw-ve-target-container="">
              <div id="contentSub">
                <div id="mw-content-subtitle"></div>
              </div>
              <div id="mw-content-text" class="mw-body-content mw-content-ltr" lang="zh" dir="ltr"><div class="mw-content-ltr mw-parser-output" lang="zh" dir="ltr"><div id="noteTA-f3e2a619" class="noteTA"><div class="noteTA-group"><div data-noteta-group-source="module" data-noteta-group="IT"></div></div></div>
<style data-mw-deduplicate="TemplateStyles:r84265675">
/* start https://zh.wikipedia.org/ */


.mw-parser-output .hlist dl,.mw-parser-output .hlist ol,.mw-parser-output .hlist ul{margin:0;padding:0}.mw-parser-output .hlist dd,.mw-parser-output .hlist dt,.mw-parser-output .hlist li{margin:0;display:inline}.mw-parser-output .hlist.inline,.mw-parser-output .hlist.inline dl,.mw-parser-output .hlist.inline ol,.mw-parser-output .hlist.inline ul,.mw-parser-output .hlist dl dl,.mw-parser-output .hlist dl ol,.mw-parser-output .hlist dl ul,.mw-parser-output .hlist ol dl,.mw-parser-output .hlist ol ol,.mw-parser-output .hlist ol ul,.mw-parser-output .hlist ul dl,.mw-parser-output .hlist ul ol,.mw-parser-output .hlist ul ul{display:inline}.mw-parser-output .hlist .mw-empty-li{display:none}.mw-parser-output .hlist dt::after{content:" :"}.mw-parser-output .hlist dd::after,.mw-parser-output .hlist li::after{content:" · ";font-weight:bold}.mw-parser-output .hlist-pipe dd::after,.mw-parser-output .hlist-pipe li::after{content:" | ";font-weight:normal}.mw-parser-output .hlist-hyphen dd::after,.mw-parser-output .hlist-hyphen li::after{content:" - ";font-weight:normal}.mw-parser-output .hlist-comma dd::after,.mw-parser-output .hlist-comma li::after{content:"、";font-weight:normal}.mw-parser-output .hlist dd:last-child::after,.mw-parser-output .hlist dt:last-child::after,.mw-parser-output .hlist li:last-child::after{content:none}.mw-parser-output .hlist ol{counter-reset:listitem}.mw-parser-output .hlist ol>li{counter-increment:listitem}.mw-parser-output .hlist ol>li::before{content:" "counter(listitem)"\a0 "}.mw-parser-output .hlist dd ol>li:first-child::before,.mw-parser-output .hlist dt ol>li:first-child::before,.mw-parser-output .hlist li ol>li:first-child::before{content:"（"counter(listitem)"\a0 "}.mw-parser-output ul.cslist,.mw-parser-output ul.sslist{margin:0;padding:0;display:inline-block;list-style:none}.mw-parser-output .cslist li,.mw-parser-output .sslist li{margin:0;display:inline-block}.mw-parser-output .cslist li::after{content:"，"}.mw-parser-output .sslist li::after{content:"；"}.mw-parser-output .cslist li:last-child::after,.mw-parser-output .sslist li:last-child::after{content:none}


/* end   https://zh.wikipedia.org/ */
</style><style data-mw-deduplicate="TemplateStyles:r84913072">
/* start https://zh.wikipedia.org/ */


.mw-parser-output .sidebar{width:22em;float:right;clear:right;margin:0.5em 0 1em 1em;background:var(--background-color-neutral-subtle,#f8f9fa);border:1px solid var(--border-color-base,#a2a9b1);padding:0.2em;text-align:center;line-height:1.4em;font-size:88%;border-collapse:collapse;display:table}body.skin-minerva .mw-parser-output .sidebar{display:table!important;float:right!important;margin:0.5em 0 1em 1em!important}.mw-parser-output .sidebar-subgroup{width:100%;margin:0;border-spacing:0}.mw-parser-output .sidebar-left{float:left;clear:left;margin:0.5em 1em 1em 0}.mw-parser-output .sidebar-none{float:none;clear:both;margin:0.5em 1em 1em 0}.mw-parser-output .sidebar-outer-title{padding:0 0.4em 0.2em;font-size:125%;line-height:1.2em;font-weight:bold}.mw-parser-output .sidebar-top-image{padding:0.4em}.mw-parser-output .sidebar-top-caption,.mw-parser-output .sidebar-pretitle-with-top-image,.mw-parser-output .sidebar-caption{padding:0.2em 0.4em 0;line-height:1.2em}.mw-parser-output .sidebar-pretitle{padding:0.4em 0.4em 0;line-height:1.2em}.mw-parser-output .sidebar-title,.mw-parser-output .sidebar-title-with-pretitle{padding:0.2em 0.8em;font-size:145%;line-height:1.2em}.mw-parser-output .sidebar-title-with-pretitle{padding:0.1em 0.4em}.mw-parser-output .sidebar-image{padding:0.2em 0.4em 0.4em}.mw-parser-output .sidebar-heading{padding:0.1em 0.4em}.mw-parser-output .sidebar-content{padding:0 0.5em 0.4em}.mw-parser-output .sidebar-content-with-subgroup{padding:0.1em 0.4em 0.2em}.mw-parser-output .sidebar-above,.mw-parser-output .sidebar-below{padding:0.3em 0.8em;font-weight:bold}.mw-parser-output .sidebar-collapse .sidebar-above,.mw-parser-output .sidebar-collapse .sidebar-below{border-top:1px solid #aaa;border-bottom:1px solid #aaa}.mw-parser-output .sidebar-navbar{text-align:right;font-size:100%;padding:0 0.4em 0.4em}.mw-parser-output .sidebar-list-title{padding:0 0.4em;text-align:left;font-weight:bold;line-height:1.6em;font-size:105%}.mw-parser-output .sidebar-list-title-c{padding:0 0.4em;text-align:center;margin:0 3.3em}@media(max-width:640px){body.mediawiki .mw-parser-output .sidebar{width:100%!important;clear:both;float:none!important;margin-left:0!important;margin-right:0!important}}body.skin--responsive .mw-parser-output .sidebar a>img{max-width:none!important}@media screen{html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-list-title,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-subgroup,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-pretitle,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-title,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-title-with-pretitle,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-heading,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-above,html.skin-theme-clientpref-night .mw-parser-output .sidebar:not(.notheme) .sidebar-below{background:inherit!important;color:inherit!important;border-color:#54595d!important}html.skin-theme-clientpref-night .mw-parser-output .sidebar a:not(.new):not(.mw-selflink):link{color:var(--color-progressive)!important}}@media screen and (prefers-color-scheme:dark){html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-list-title,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-subgroup,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-pretitle,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-title,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-title-with-pretitle,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-heading,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-above,html.skin-theme-clientpref-os .mw-parser-output .sidebar:not(.notheme) .sidebar-below{background:inherit!important;color:inherit!important;border-color:#54595d!important}html.skin-theme-clientpref-os .mw-parser-output .sidebar a:not(.new):not(.mw-selflink):link{color:var(--color-progressive)!important}}@media print{body.ns-0 .mw-parser-output .sidebar{display:none!important}}


/* end   https://zh.wikipedia.org/ */
</style><table class="sidebar nomobile nowraplinks"><tbody><tr><th class="sidebar-title"><a href="C%E6%A8%99%E6%BA%96%E5%87%BD%E5%BC%8F%E5%BA%AB" title="C標準函式庫">C标准函数库</a></th></tr><tr><th class="sidebar-heading">
一般</th></tr><tr><td class="sidebar-content" style="text-align: left">
<ul><li><a href="Stdlib.h#数据类型" title="Stdlib.h">数据类型</a></li>
<li><a href="Ctype.h" title="Ctype.h">字符类型</a></li>
<li><a href="String.h" title="String.h">字符串</a></li>
<li><a href="Math.h" title="Math.h">数学</a></li>
<li><a href="Stdio.h" title="Stdio.h">文件输入/输出</a></li>
<li><a href="Time.h" title="Time.h">日期/时间</a></li>
<li><a href="Locale.h" title="Locale.h">本地化</a></li>
<li><a href="Stdlib.h#函数" title="Stdlib.h">内存分配</a></li>
<li><a href="Stdlib.h#函数" title="Stdlib.h">过程控制</a></li>
<li><a href="Signal.h" title="Signal.h">信号</a></li>
<li><a href="C%E6%9B%BF%E4%BB%A3%E6%A0%87%E8%AE%B0" title="C替代标记">替代标记</a></li></ul></td>
</tr><tr><th class="sidebar-heading">
杂项</th></tr><tr><td class="sidebar-content" style="text-align: left">
<ul><li><code>&lt;<a href="Assert.h" title="Assert.h">assert.h</a>&gt;</code></li>
<li><code>&lt;<a href="Errno.h" title="Errno.h">errno.h</a>&gt;</code></li>
<li><code>&lt;<a class="mw-selflink selflink">setjmp.h</a>&gt;</code></li>
<li><code>&lt;<a href="Stdarg.h" title="Stdarg.h">stdarg.h</a>&gt;</code></li></ul></td>
</tr><tr><td class="sidebar-navbar" style="line-height:1.6"><style data-mw-deduplicate="TemplateStyles:r84244141">
/* start https://zh.wikipedia.org/ */


.mw-parser-output .navbar{display:inline;font-weight:normal}.mw-parser-output .navbar-collapse{float:left;text-align:left}.mw-parser-output .navbar-boxtext{word-spacing:0}.mw-parser-output .navbar ul{display:inline-block;white-space:nowrap;line-height:inherit}.mw-parser-output .navbar-brackets::before{margin-right:-0.125em;content:"[ "}.mw-parser-output .navbar-brackets::after{margin-left:-0.125em;content:" ]"}.mw-parser-output .navbar li{word-spacing:-0.125em}.mw-parser-output .navbar a>span,.mw-parser-output .navbar a>abbr{text-decoration:inherit}.mw-parser-output .navbar-mini abbr{font-variant:small-caps;border-bottom:none;text-decoration:none;cursor:inherit}.mw-parser-output .navbar-ct-full{font-size:110%;margin:0 8em}.mw-parser-output .navbar-ct-mini{font-size:110%;margin:0 5em}html.skin-theme-clientpref-night .mw-parser-output .navbar li a abbr{color:var(--color-base)!important}@media(prefers-color-scheme:dark){html.skin-theme-clientpref-os .mw-parser-output .navbar li a abbr{color:var(--color-base)!important}}@media print{.mw-parser-output .navbar{display:none!important}}


/* end   https://zh.wikipedia.org/ */
</style></td></tr></tbody></table> 
<p>
<b>setjmp.h</b>是<a href="C%E6%A8%99%E6%BA%96%E5%87%BD%E6%95%B8%E5%BA%AB" class="mw-redirect" title="C標準函數庫">C标准函数库</a>中提供“非本地跳转”的<a href="%E5%A4%B4%E6%96%87%E4%BB%B6" title="头文件">头文件</a>：<a href="%E6%8E%A7%E5%88%B6%E6%B5%81" class="mw-redirect" title="控制流">控制流</a>偏离了通常的子程序调用与返回序列。互补的两个函数setjmp与longjmp提供了这种功能。
</p><p>setjmp/longjmp的典型用途是<a href="%E4%BE%8B%E5%A4%96%E5%A4%84%E7%90%86_(%E7%BC%96%E7%A8%8B)" title="例外处理 (编程)">异常处理</a>机制的实现：利用longjmp恢复程序或线程的状态，甚至可以跳过栈中多层的函数调用。
</p>

<div class="mw-heading mw-heading2"><h2 id="成员函数"><span id=".E6.88.90.E5.91.98.E5.87.BD.E6.95.B0"></span>成员函数</h2></div>
<table class="wikitable">

<tbody><tr>
<td><code>int setjmp(jmp_buf&nbsp;env)</code></td>
<td>建立本地的<code>jmp_buf</code>缓冲区并且初始化，用于将来跳转回此处。这个子程序<sup id="cite_ref-macro_1-0" class="reference"><a href="#cite_note-macro-1"><span class="cite-bracket">[</span>1<span class="cite-bracket">]</span></a></sup> 保存程序的调用环境于<code>env</code>参数所指的缓冲区，<code>env</code>将被<code>longjmp</code>使用。如果是从<code>setjmp</code>直接调用返回，<code>setjmp</code>返回值为0。如果是从<code>longjmp</code>恢复的程序调用环境返回，<code>setjmp</code>返回非零值。
</td></tr>
<tr>
<td><code>void longjmp(jmp_buf&nbsp;env, int&nbsp;value)</code></td>
<td>恢复<code>env</code>所指的缓冲区中的程序调用环境上下文，<code>env</code>所指缓冲区的内容是由<code>setjmp</code>子程序<sup id="cite_ref-macro_1-1" class="reference"><a href="#cite_note-macro-1"><span class="cite-bracket">[</span>1<span class="cite-bracket">]</span></a></sup>调用所保存。<code>value</code>的值从<code>longjmp</code>传递给<code>setjmp</code>。<code>longjmp</code>完成后，程序从对应的<code>setjmp</code>调用处继续执行，如同<code>setjmp</code>调用刚刚完成。如果<code>value</code>传递给<code>longjmp</code>零值，<code>setjmp</code>的返回值为1；否则，<code>setjmp</code>的返回值为<code>value</code>。
</td></tr>
</tbody></table>
<p><code>setjmp</code>保存当前的环境（即程序的状态）到平台相关的一个数据结构 (<code>jmp_buf</code>)，该数据结构在随后程序执行的某一点可被 <code>longjmp</code>用于恢复程序的状态到<code>setjmp</code>调用所保存到<code>jmp_buf</code>时的原样。这一过程可以认为是"跳转"回<code>setjmp</code>所保存的程序执行状态。<code>setjmp</code>的返回值指出控制是正常到达该点还是通过调用<code>longjmp</code>恢复到该点。因此有编程的惯用法: <code>if( setjmp(x) ){/* handle longjmp(x) */}</code>。
</p>
<div class="mw-heading mw-heading2"><h2 id="成员类型"><span id=".E6.88.90.E5.91.98.E7.B1.BB.E5.9E.8B"></span>成员类型</h2></div>
<table class="wikitable">

<tbody><tr>
<td><code>jmp_buf</code></td>
<td>数组类型，例如<code>struct int[16]</code><sup id="cite_ref-2" class="reference"><a href="#cite_note-2"><span class="cite-bracket">[</span>2<span class="cite-bracket">]</span></a></sup>或<code>struct __jmp_buf_tag</code><sup id="cite_ref-3" class="reference"><a href="#cite_note-3"><span class="cite-bracket">[</span>3<span class="cite-bracket">]</span></a></sup>，用于保存恢复调用环境所需的信息。
</td></tr></tbody></table>
<div class="mw-heading mw-heading2"><h2 id="告诫与限制"><span id=".E5.91.8A.E8.AF.AB.E4.B8.8E.E9.99.90.E5.88.B6"></span>告诫与限制</h2></div>
<p><code>longjmp</code>实现了非本地跳转，微软的IA32程序设计环境中正常的"<a href="%E8%B0%83%E7%94%A8%E6%A0%88#栈解绕" class="mw-redirect" title="调用栈">栈解开</a>"因而没有发生，所以诸如栈中已定义的局部变量的析构函数的调用（用于销毁该局部变量）都没有执行。所有依赖于栈解开调用析构函数所做的扫尾工作，如关闭文件、释放堆内存块等都没有做。但在微软的X64程序设计环境，<code>longjmp</code>启动了正常的"栈解开"。<sup id="cite_ref-4" class="reference"><a href="#cite_note-4"><span class="cite-bracket">[</span>4<span class="cite-bracket">]</span></a></sup>
</p><p>如果<code>setjmp</code>所在的函数已经调用返回了，那么<code>longjmp</code>使用该处<code>setjmp</code>所填写的对应<code>jmp_buf</code>缓冲区将不再有效。这是因为<code>longjmp</code>所要返回的"栈帧"(stack frame)已经不再存在了，程序返回到一个不再存在的执行点，很可能覆盖或者弄坏程序栈.<sup id="cite_ref-5" class="reference"><a href="#cite_note-5"><span class="cite-bracket">[</span>5<span class="cite-bracket">]</span></a></sup><sup id="cite_ref-6" class="reference"><a href="#cite_note-6"><span class="cite-bracket">[</span>6<span class="cite-bracket">]</span></a></sup>
</p>
<div class="mw-heading mw-heading2"><h2 id="使用例子"><span id=".E4.BD.BF.E7.94.A8.E4.BE.8B.E5.AD.90"></span>使用例子</h2></div>
<div class="mw-heading mw-heading3"><h3 id="简单例子"><span id=".E7.AE.80.E5.8D.95.E4.BE.8B.E5.AD.90"></span>简单例子</h3></div>
<div class="mw-highlight mw-highlight-lang-c mw-content-ltr" dir="ltr"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;setjmp.h&gt;</span>

<span class="k">static</span><span class="w"> </span><span class="kt">jmp_buf</span><span class="w"> </span><span class="n">buf</span><span class="p">;</span>

<span class="kt">void</span><span class="w"> </span><span class="nf">second</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="n">printf</span><span class="p">(</span><span class="s">"second</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w">         </span><span class="c1">// 打印</span>
<span class="w">    </span><span class="n">longjmp</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span><span class="w">             </span><span class="c1">// 跳回setjmp的调用处 - 使得setjmp返回值为1</span>
<span class="p">}</span>

<span class="kt">void</span><span class="w"> </span><span class="nf">first</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="n">second</span><span class="p">();</span>
<span class="w">    </span><span class="n">printf</span><span class="p">(</span><span class="s">"first</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w">          </span><span class="c1">// 不可能执行到此行</span>
<span class="p">}</span>

<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">   </span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="o">!</span><span class="w"> </span><span class="n">setjmp</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="n">first</span><span class="p">();</span><span class="w">                </span><span class="c1">// 进入此行前，setjmp返回0</span>
<span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">                    </span><span class="c1">// 当longjmp跳转回，setjmp返回1，因此进入此行</span>
<span class="w">        </span><span class="n">printf</span><span class="p">(</span><span class="s">"main</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w">       </span><span class="c1">// 打印</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>上述程序将输出: 
</p>
<pre>second
main
</pre>
<p>注意到虽然<code>first()</code>子程序被调用，"<code>first</code>"不可能被打印。"<code>main</code>"被打印，因为条件语句<code>if (&nbsp;! setjmp(buf) )</code>被执行第二次。
</p>
<div class="mw-heading mw-heading3"><h3 id="异常处理"><span id=".E5.BC.82.E5.B8.B8.E5.A4.84.E7.90.86"></span>异常处理</h3></div>
<p>在下例中，<code>setjmp</code>被用于包住一个例外处理，类似<a href="%E4%BE%8B%E5%A4%96%E5%A4%84%E7%90%86_(%E7%BC%96%E7%A8%8B)" title="例外处理 (编程)"><code>try</code></a>。<code>longjmp</code>调用类似于<code>throw</code>语句，允许一个异常返回给<code>setjmp</code>一个异常值。下属代码示例遵从<a href="C99" title="C99">1999 ISO C standard</a>与<a href="Single_UNIX_Specification" class="mw-redirect" title="Single UNIX Specification">Single UNIX Specification</a>：仅在特定范围内引用<code>setjmp</code>
</p>
<ul><li><code>if</code>，<code>switch</code>或它们的嵌套使用的条件表达式</li>
<li>上述情况下与<code>!</code>一起使用或者与整数常值比较</li>
<li>作为单独的语句(不使用其返回值)</li></ul>
<p>遵从上述规则使得创建程序环境缓冲区更为容易。更一般的使用<code>setjmp</code>可能引起<a href="%E6%9C%AA%E5%AE%9A%E4%B9%89%E8%A1%8C%E4%B8%BA" title="未定义行为">未定义行为</a>，如破坏局部变量；编译器被要求保护或警告这些用法。但轻微的复杂用法如<code>switch ((exception_type = setjmp(env))) { }</code>在文献与实践中是常见的，并保持了相当的可移植性。
</p>
<div class="mw-highlight mw-highlight-lang-c mw-content-ltr" dir="ltr"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdio.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;stdlib.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;string.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;setjmp.h&gt;</span>
<span class="w"> </span>
<span class="kt">void</span><span class="w"> </span><span class="nf">first</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="kt">void</span><span class="w"> </span><span class="nf">second</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="w"> </span>
<span class="cm">/* This program's output is:</span>
<span class="cm"> </span>
<span class="cm">calling first</span>
<span class="cm">calling second</span>
<span class="cm">entering second</span>
<span class="cm">second failed with type 3 exception; remapping to type 1.</span>
<span class="cm">first failed, exception type 1</span>
<span class="cm"> </span>
<span class="cm">*/</span>
<span class="w"> </span>
<span class="cm">/* Use a file scoped static variable for the exception stack so we can access</span>
<span class="cm"> * it anywhere within this translation unit. */</span>
<span class="k">static</span><span class="w"> </span><span class="kt">jmp_buf</span><span class="w"> </span><span class="n">exception_env</span><span class="p">;</span>
<span class="k">static</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">exception_type</span><span class="p">;</span>
<span class="w"> </span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="k">volatile</span><span class="w"> </span><span class="n">mem_buffer</span><span class="p">;</span>
<span class="w"> </span>
<span class="w">    </span><span class="n">mem_buffer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">setjmp</span><span class="p">(</span><span class="n">exception_env</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="cm">/* if we get here there was an exception */</span>
<span class="w">        </span><span class="n">printf</span><span class="p">(</span><span class="s">"first failed, exception type %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">exception_type</span><span class="p">);</span>
<span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="cm">/* Run code that may signal failure via longjmp. */</span>
<span class="w">        </span><span class="n">printf</span><span class="p">(</span><span class="s">"calling first</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w">        </span><span class="n">first</span><span class="p">();</span>
<span class="w">        </span><span class="n">mem_buffer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="mi">300</span><span class="p">);</span><span class="w"> </span><span class="cm">/* allocate a resource */</span>
<span class="w">        </span><span class="n">printf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span><span class="n">strcpy</span><span class="p">((</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">mem_buffer</span><span class="p">,</span><span class="w"> </span><span class="s">"first succeeded!"</span><span class="p">));</span><span class="w"> </span><span class="cm">/* ... this will not happen */</span>
<span class="w">    </span><span class="p">}</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">mem_buffer</span><span class="p">)</span>
<span class="w">        </span><span class="n">free</span><span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">mem_buffer</span><span class="p">);</span><span class="w"> </span><span class="cm">/* carefully deallocate resource */</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="w"> </span>
<span class="kt">void</span><span class="w"> </span><span class="nf">first</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="kt">jmp_buf</span><span class="w"> </span><span class="n">my_env</span><span class="p">;</span>
<span class="w"> </span>
<span class="w">    </span><span class="n">printf</span><span class="p">(</span><span class="s">"calling second</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w">    </span><span class="n">memcpy</span><span class="p">(</span><span class="n">my_env</span><span class="p">,</span><span class="w"> </span><span class="n">exception_env</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">jmp_buf</span><span class="p">));</span>
<span class="w">    </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">setjmp</span><span class="p">(</span><span class="n">exception_env</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="mi">3</span><span class="p">:</span>
<span class="w">            </span><span class="cm">/* if we get here there was an exception. */</span>
<span class="w">            </span><span class="n">printf</span><span class="p">(</span><span class="s">"second failed with type 3 exception; remapping to type 1.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w">            </span><span class="n">exception_type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>

<span class="w">        </span><span class="k">default</span><span class="o">:</span><span class="w"> </span><span class="cm">/* fall through */</span>
<span class="w">            </span><span class="n">memcpy</span><span class="p">(</span><span class="n">exception_env</span><span class="p">,</span><span class="w"> </span><span class="n">my_env</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">jmp_buf</span><span class="p">));</span><span class="w"> </span><span class="cm">/* restore exception stack */</span>
<span class="w">            </span><span class="n">longjmp</span><span class="p">(</span><span class="n">exception_env</span><span class="p">,</span><span class="w"> </span><span class="n">exception_type</span><span class="p">);</span><span class="w"> </span><span class="cm">/* continue handling the exception */</span>

<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="mi">0</span><span class="p">:</span>
<span class="w">            </span><span class="cm">/* normal, desired operation */</span>
<span class="w">            </span><span class="n">second</span><span class="p">();</span>
<span class="w">            </span><span class="n">printf</span><span class="p">(</span><span class="s">"second succeeded</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w">  </span><span class="cm">/* not reached */</span>
<span class="w">    </span><span class="p">}</span>
<span class="w">    </span><span class="n">memcpy</span><span class="p">(</span><span class="n">exception_env</span><span class="p">,</span><span class="w"> </span><span class="n">my_env</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">jmp_buf</span><span class="p">));</span><span class="w"> </span><span class="cm">/* restore exception stack */</span>
<span class="p">}</span>
<span class="w"> </span>
<span class="kt">void</span><span class="w"> </span><span class="nf">second</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="n">printf</span><span class="p">(</span><span class="s">"entering second</span><span class="se">\n</span><span class="s">"</span><span class="w"> </span><span class="p">);</span><span class="w"> </span><span class="cm">/* reached */</span>
<span class="w">    </span><span class="n">exception_type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span>
<span class="w">    </span><span class="n">longjmp</span><span class="p">(</span><span class="n">exception_env</span><span class="p">,</span><span class="w"> </span><span class="n">exception_type</span><span class="p">);</span><span class="w"> </span><span class="cm">/* declare that the program has failed */</span>
<span class="w">    </span><span class="n">printf</span><span class="p">(</span><span class="s">"leaving second</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w"> </span><span class="cm">/* not reached */</span>
<span class="p">}</span>
</pre></div>
<div class="mw-heading mw-heading2"><h2 id="用于信号处理"><span id=".E7.94.A8.E4.BA.8E.E4.BF.A1.E5.8F.B7.E5.A4.84.E7.90.86"></span>用于信号处理</h2></div>
<p>在<a href="Signal.h" title="Signal.h">信号处理机制</a>中，进程在检查收到的信号，会从原来的系统调用中直接返回，而不是等到该调用完成。这种进程突然改变其上下文的情况，就是通过使用setjmp和longjmp来实现的。setjmp将保存的上下文载入用户空间，并继续在旧的上下文中继续执行。这就是说，进程执行一个系统调用，当因为资源或其他原因要去睡眠时，内核为进程作了一次setjmp，如果在睡眠中被信号唤醒，进程不能再进入睡眠时，内核为进程调用longjmp，该操作是内核为进程将现在的上下文切换成原先通过setjmp调用保存在进程用户区的上下文，这样就使得进程可以恢复等待资源前的状态，而且内核为setjmp返回1，使得进程知道该次系统调用失败。
</p>
<div class="mw-heading mw-heading2"><h2 id="参考文献"><span id=".E5.8F.82.E8.80.83.E6.96.87.E7.8C.AE"></span>参考文献</h2></div>
<div class="reflist" style="list-style-type: decimal;">
<ol class="references">
<li id="cite_note-macro-1"><span class="mw-cite-backlink">^ <a href="#cite_ref-macro_1-0"><sup><b>1.0</b></sup></a> <a href="#cite_ref-macro_1-1"><sup><b>1.1</b></sup></a></span> <span class="reference-text">ISO C标准要求<code>setjmp</code>必须是宏实现，但POSIX明确称未定义<code>setjmp</code>是宏实现还是函数实现。</span>
</li>
<li id="cite_note-2"><span class="mw-cite-backlink"><b><a href="#cite_ref-2">^</a></b></span> <span class="reference-text">Visual Studio 2008用法</span>
</li>
<li id="cite_note-3"><span class="mw-cite-backlink"><b><a href="#cite_ref-3">^</a></b></span> <span class="reference-text"><a href="GNU_C_%E5%87%BD%E5%BC%8F%E5%BA%AB" class="mw-redirect" title="GNU C 函式庫">GNU C 函式庫</a> 2.7的用法</span>
</li>
<li id="cite_note-4"><span class="mw-cite-backlink"><b><a href="#cite_ref-4">^</a></b></span> <span class="reference-text">Microsoft Visual C++ 2010 x32或x64与Intel ICC 2011 (version 12) x32或x64，编译结果都是<code>longjmp</code>启动了正常的"栈解开"。但GCC 4.4 x32版编译的<code>longjmp</code>不执行"栈解开"。可见，是否“栈解开”不具有移植性。</span>
</li>
<li id="cite_note-5"><span class="mw-cite-backlink"><b><a href="#cite_ref-5">^</a></b></span> <span class="reference-text"><style data-mw-deduplicate="TemplateStyles:r92366446">
/* start https://zh.wikipedia.org/ */


.mw-parser-output cite.citation{font-style:inherit;word-wrap:break-word}.mw-parser-output .citation q{quotes:"\"""\"""'""'"}.mw-parser-output .citation:target{background-color:rgba(0,127,255,0.133)}.mw-parser-output .id-lock-free.id-lock-free a{background:url("./_mw_/Lock-green.svg")right 0.1em center/9px no-repeat}.mw-parser-output .id-lock-limited.id-lock-limited a,.mw-parser-output .id-lock-registration.id-lock-registration a{background:url("./_mw_/Lock-gray-alt-2.svg")right 0.1em center/9px no-repeat}.mw-parser-output .id-lock-subscription.id-lock-subscription a{background:url("./_mw_/Lock-red-alt-2.svg")right 0.1em center/9px no-repeat}.mw-parser-output .cs1-ws-icon a{background:url("./_mw_/Wikisource-logo.svg")right 0.1em center/12px no-repeat}body:not(.skin-timeless):not(.skin-minerva) .mw-parser-output .id-lock-free a,body:not(.skin-timeless):not(.skin-minerva) .mw-parser-output .id-lock-limited a,body:not(.skin-timeless):not(.skin-minerva) .mw-parser-output .id-lock-registration a,body:not(.skin-timeless):not(.skin-minerva) .mw-parser-output .id-lock-subscription a,body:not(.skin-timeless):not(.skin-minerva) .mw-parser-output .cs1-ws-icon a{background-size:contain;padding:0 1em 0 0}.mw-parser-output .cs1-code{color:inherit;background:inherit;border:none;padding:inherit}.mw-parser-output .cs1-hidden-error{display:none;color:var(--color-error,#d33)}.mw-parser-output .cs1-visible-error{color:var(--color-error,#d33)}.mw-parser-output .cs1-maint{display:none;color:#085;margin-left:0.3em}.mw-parser-output .cs1-kern-left{padding-left:0.2em}.mw-parser-output .cs1-kern-right{padding-right:0.2em}.mw-parser-output .citation .mw-selflink{font-weight:inherit}@media screen{.mw-parser-output .cs1-format{font-size:95%}html.skin-theme-clientpref-night .mw-parser-output .cs1-maint{color:#18911f}}@media screen and (prefers-color-scheme:dark){html.skin-theme-clientpref-os .mw-parser-output .cs1-maint{color:#18911f}}


/* end   https://zh.wikipedia.org/ */
</style><cite class="citation web"><a rel="nofollow" class="external text" href="http://www.cs.utk.edu/~mbeck/classes/cs560/360/notes/Setjmp/lecture.html">CS360 Lecture Notes — Setjmp and Longjmp</a>.  <span class="reference-accessdate"> [<span class="nowrap">2011-06-06</span>]</span>. （原始内容<a rel="nofollow" class="external text" href="https://web.archive.org/web/20100704192041/http://www.cs.utk.edu/~mbeck/classes/cs560/360/notes/Setjmp/lecture.html">存档</a>于2010-07-04）.</cite><span title="ctx_ver=Z39.88-2004&amp;rfr_id=info%3Asid%2Fzh.wikipedia.org%3ASetjmp.h&amp;rft.btitle=CS360+Lecture+Notes+%E2%80%94+Setjmp+and+Longjmp&amp;rft.genre=unknown&amp;rft_id=http%3A%2F%2Fwww.cs.utk.edu%2F~mbeck%2Fclasses%2Fcs560%2F360%2Fnotes%2FSetjmp%2Flecture.html&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook" class="Z3988"><span style="display:none;">&nbsp;</span></span></span>
</li>
<li id="cite_note-6"><span class="mw-cite-backlink"><b><a href="#cite_ref-6">^</a></b></span> <span class="reference-text"><cite class="citation web"><a rel="nofollow" class="external text" href="http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=setjmp(3)&amp;msection=">setjmp(3)</a>.  <span class="reference-accessdate"> [<span class="nowrap">2011-06-06</span>]</span>. （原始内容<a rel="nofollow" class="external text" href="https://web.archive.org/web/20090726081425/http://www.uwm.edu/cgi-bin/IMT/wwwman?topic=setjmp%283%29&amp;msection=">存档</a>于2009-07-26）.</cite><span title="ctx_ver=Z39.88-2004&amp;rfr_id=info%3Asid%2Fzh.wikipedia.org%3ASetjmp.h&amp;rft.btitle=setjmp%283%29&amp;rft.genre=unknown&amp;rft_id=http%3A%2F%2Fwww.uwm.edu%2Fcgi-bin%2FIMT%2Fwwwman%3Ftopic%3Dsetjmp%283%29%26msection%3D&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook" class="Z3988"><span style="display:none;">&nbsp;</span></span></span>
</li>
</ol></div>
<div class="mw-heading mw-heading2"><h2 id="外部链接"><span id=".E5.A4.96.E9.83.A8.E9.93.BE.E6.8E.A5"></span>外部链接</h2></div>
<ul><li><a rel="nofollow" class="external text" href="http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html">Exceptions in C with Longjmp and Setjmp</a>（<a rel="nofollow" class="external text" href="https://web.archive.org/web/20110615175107/http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html">页面存档备份</a>，存于<a href="%E4%BA%92%E8%81%94%E7%BD%91%E6%A1%A3%E6%A1%88%E9%A6%86" title="互联网档案馆">互联网档案馆</a>）</li></ul></div><!--htdig_noindex--><div><div class="zim-footer">
    This article is issued from <a class="external text" title="Last edited on 2025-12-15" href="https://zh.wikipedia.org/wiki/?title=Setjmp.h&amp;oldid=90690899">Wikipedia</a>. The text is available under <a class="external text" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh">Creative Commons Attribution-Share Alike 4.0</a> unless otherwise noted. Additional terms may apply for the media files.
</div>
</div><!--/htdig_noindex--></div>
            </div>
          </main>
        </div>
      </div>
    </div>
     <script src="./_webp_/webpHandler.js"></script>
  

</body></html>