属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
setjmp(),sigsetjmp()Thread safetyMT-Safe
longjmp(),siglongjmp()Thread safetyMT-Safe

返回值

直接调用setjmp()和sigsetjmp()时返回0;在longjmp()或siglongjmp()之后发生的"假"返回中,返回val中指定的非零值。

longjmp()或siglongjmp()函数不会返回。

SETJMP - Linux手册页

Linux程序员手册 第3部分
更新日期: 2017-03-13

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

名称

setjmp,sigsetjmp,longjmp,siglongjmp-执行非本地goto

另外参见

信号(7),信号安全(7)

说明

本页描述的功能用于执行"非本地操作":将执行从一个功能转移到另一个功能中的预定位置。 setjmp()函数动态地建立控制对象,以后将控制权转移到该目标,而longjmp()执行执行的转移。

setjmp()函数将有关调用环境的各种信息(通常是堆栈指针,指令指针,可能还有其他寄存器的值和信号掩码)保存在缓冲区env中,以供longjmp()稍后使用。在这种情况下,setjmp()返回0。

longjmp()函数使用env中保存的信息将控制权转移回调用setjmp()的位置,并在调用setjmp()时将堆栈恢复("回卷")为其状态。另外,根据实现方式(请参阅"注释"),某些其他寄存器和过程信号掩码的值可能会在setjmp()调用时恢复为其状态。

在成功执行longjmp()之后,执行将继续,就像setjmp()再次返回一样。此"假"返回可以与真正的setjmp()调用区分开,因为"假"返回返回val中提供的值。如果程序员错误地在val中传递了值0,则"假"返回将返回1。

sigsetjmp() and siglongjmp()

sigsetjmp()和siglongjmp()也执行非本地指令,但是提供了对过程信号掩码的可预测处理。

当且仅当提供给sigsetjmp()的savesigs参数为非零时,该进程的当前信号掩码才保存在env中,如果以后再用此env执行siglongjmp(),则该过程将被恢复。

遵循规范

setjmp(),longjmp():POSIX.1-2001,POSIX.1-2008,C89,C99。

sigsetjmp(),siglongjmp():POSIX.1-2001,POSIX.1-2008。

备注

POSIX没有指定setjmp()是否保存信号掩码(稍后在longjmp()期间恢复)。在系统V中不会。在4.3BSD中它会,并且函数_setjmp()不会。 Linux下的行为取决于glibc版本和功能测试宏的设置。在具有2.19之前的glibc版本的Linux上,默认情况下setjmp()遵循System V行为,但是如果显式定义了_BSD_SOURCE功能测试宏并且未定义_POSIX_SOURCE_POSIX_C_SOURCE_XOPEN_SOURCE,_GNU_SOURCE或_SVID_SOURCE,则会提供BSD行为。从glibc 2.19开始,仅公开System V版本的setjmp()。需要BSD语义的程序应使用非零的savesigs参数将对setjmp()的调用替换为对sigsetjmp()的调用。

setjmp()和longjmp()可用于处理深度嵌套的函数调用中的错误,或者允许信号处理程序将控制权传递给程序中的特定点,而不是返回到处理程序中断主程序的点。在后一种情况下,如果要便携式保存和恢复信号掩码,请使用sigsetjmp()和siglongjmp()。另请参见下面有关程序可读性的讨论。

编译器可以将变量优化到寄存器中,并且longjmp()可以恢复除堆栈指针和程序计数器之外的其他寄存器的值。因此,如果满足以下所有条件,则在调用longjmp()之后未指定自动变量的值:

*
它们在进行相应的setjmp()调用的函数中是本地的;
*
它们的值在setjmp()和longjmp()的调用之间改变;和
*
它们没有被声明为volatile。

类似的注释适用于siglongjmp()。

Nonlocal gotos and program readability

尽管可以被滥用,但传统的C" goto"语句至少具有以下优点:词汇提示(goto语句和目标标签)使程序员可以轻松地感知控制流。非本地的getos没有提供这样的提示:多个setjmp()调用可能使用相同的jmp_buf变量,以便该变量的内容可能在应用程序的生存期内发生变化。因此,程序员可能被迫执行代码的详细阅读,以确定特定longjmp()调用的动态目标。 (为了使程序员的生活更轻松,每个setjmp()调用都应使用唯一的jmp_buf变量。)

进一步增加了难度,setjmp()和longjmp()调用甚至可能不在同一源代码模块中。

总之,非本地的gotos会使程序更难于理解和维护,并且如果可能的话,应该使用替代方法。

Caveats

如果调用setjmp()的函数在调用longjmp()之前返回,则该行为未定义。一定会导致某种微妙或微妙的混乱。

如果在多线程程序中,longjmp()调用使用了由另一个线程中对setjmp()的调用初始化的env缓冲区,则该行为未定义。

POSIX.1-2008技术勘误2将longjmp()和siglongjmp()添加到异步信号安全功能列表中。但是,该标准建议避免使用信号处理程序中的这些功能,并继续指出,如果这些信号是从信号处理程序中调用的,则中断了对非异步信号安全功能(或类似方法,例如作为与从初始调用返回main()时发生的exit(3)等效的步骤,如果程序随后对非异步信号安全函数进行了调用,则该行为是不确定的。避免未定义行为的唯一方法是确保以下一项:

*
从信号处理程序中长时间跳转之后,该程序不会调用任何非异步信号安全函数,并且不会从初始调用返回到main()。
*
从初始调用返回到main()之后,在每次调用非异步信号安全函数时都必须阻止其处理程序执行跳远的任何信号,并且不会调用任何非异步信号安全函数。

语法

#include <setjmp.h>

int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savesigs);

void longjmp(jmp_buf env, int val);
void siglongjmp(sigjmp_buf env, int val);

glibc的功能测试宏要求(请参阅feature_test_macros(7)):

setjmp():请参见注释。

sigsetjmp():_POSIX_C_SOURCE

日期:2019-08-20 18:01:20 来源:oir作者:oir