在本地 jmp_buf 中使用 setjmp 和 longjmp
Using setjmp and longjmp with a local jmp_buf
如果一个localjmp_buf
实际上是用寄存器而不是栈内存来表示的,setjmp
或者longjmp
有没有可能导致local[=]的内容13=] 在 setjmp
returns 来自 longjmp
?
时不确定
建议重复 在全局变量的上下文中询问。有人建议,因为答案解释了变量没有以阻止它随后被调用的方式修改,这也充分回答了局部变量的问题。
但是,局部变量的处理方式不同于全局变量。特别是,如果本地 jmp_buf
变量实际上保存在寄存器中而不是内存中,则 longjmp
之后的恢复可能不会呈现可重用的 jmp_buf
变量。
作为一项学术练习,我尝试使用 setjmp
代替 goto
。为了将循环替换保留在函数本地,使用的 jmp_buf
也是一个局部变量。
void foo (int n) {
jmp_buf jb;
volatile int i;
i = setjmp(jb);
if (i < n) {
do_stuff(i);
longjmp(jb, ++i);
}
}
我了解在 setjmp
调用和 longjmp
调用之间修改的非易失性局部变量在 longjmp
之后未指定。但是,我对局部 jmp_buf
变量本身很好奇,特别是在 jmp_buf
变量由寄存器而不是堆栈上的内存表示的情况下。
不清楚 longjmp
本身是否可以被认为是可以修改局部 jmp_buf
变量的东西,以及这是否意味着它的内容在 setjmp
returns 时未指定在调用 longjmp
.
之后
我以为我可以通过将 jb
声明为 volatile
来轻松解决问题,但这触发了警告(我将其视为错误):
... error: passing argument 1 of ‘_setjmp’ discards ‘volatile’ qualifier from pointer target type [-Werror=discarded-qualifiers]
setjmp(jb);
^~
此外,setjmp
的规范并没有说明它是在设置 jmp_buf
之后还是在设置 jmp_buf
之前保存寄存器值。
如果我需要关心它,我可以创建一个 jmp_buf
的可变副本并复制它的内容。但是,如果不需要,我想避免这种情况。
没关系。
在相关说明中,您不需要 i
上的 volatile
,因为它是由 setjmp()
分配给的。
仔细阅读 longjmp()
的手册页和我的 K&R C 副本,jb
的内容仅在您的函数体内无效,这意味着如果有第二次调用 longjmp()
,它将看到 jb
的有效视图。在合理的假设下,有效代码不会在较新的标准版本中变得无效,这在今天仍然适用。
TL;DR 你不需要标记 jmp_buf
volatile 类型的变量。
C11 standard 节 §7.13.2.1 第 3 点指出:
All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp
function was called, except that the values of
objects of automatic storage duration that are local to the function containing the
invocation of the corresponding setjmp
macro that do not have volatile
-qualified type
and have been changed between the setjmp
invocation and longjmp
call are
indeterminate.
您的 jmp_buf
对象在 setjmp(jb)
和 longjmp(jb, ++i)
之间没有变化。调用之间唯一改变的变量是 i
,按照标准建议声明为 volatile
。
所以,为了回答你的问题,longjmp
不能单独“修改本地 jmp_buf
的内容 [以这种方式] 会导致其内容在 [=11 时未定义=] returns”,但是通过其他方式修改两次调用之间的jmp_buf
肯定会造成麻烦。
TL;DR 由于标准不明确,最好把a的值local jmp_buf
在 local longjmp
.
之后不确定
ISO/IEC 9899:2018 §17.13.1.1 ¶2 描述了 setjmp
的行为,而 ¶3 描述了 return.
上发生的事情
The setjmp
macro saves its calling environment in its jmp_buf
argument for later use by the longjmp
function.
...
If the return is from a direct invocation, the setjmp
macro returns the value zero. If the return is from a call to the longjmp
function, the setjmp
macro returns a nonzero value.
我们推断 setjmp
的成功 return 会导致初始化的 jmp_buf
参数。但是,没有提及初始化是否考虑到 jmp_buf
本身具有自动存储持续时间(因此,它本身可以由寄存器而不是内存表示)。
ISO/IEC 9899:2018 §7.13.2.1 ¶3 描述了 longjmp
的行为,措辞与 引用的 2011 年文本相同:
All accessible objects have values, and all other components of the abstract machine254) have state,
as of the time the longjmp
function was called, except that the values of objects of automatic storage
duration that are local to the function containing the invocation of the corresponding setjmp
macro
that do not have volatile-qualified type and have been changed between the setjmp
invocation and
longjmp
call are indeterminate.
254)This includes, but is not limited to, the floating-point status flags and the state of open files.
不过,between这个词的意思有点难以捉摸。该标准可以明确指定 between 的上下文,表示在 setjmp
完成之后。例如,措辞可以是:
... changed between the setjmp
return and longjmp
call are indeterminate.
当前的措辞表明,应该将 setjmp
本身的调用包括在内,作为可能触发不确定条件的东西。
但是,longjmp
的 return 的语义有可能涵盖这个问题。 ISO/IEC 9899:2018 §17.13.2.1 ¶4 状态:
After longjmp
is completed, thread execution continues as if the corresponding invocation of the
setjmp
macro had just returned the value specified by val
. ...
这句话可以解释为 setjmp
的调用语义是相同的,无论是来自直接调用的 return 还是来自 longjmp
的 return功能。也就是说,setjmp
的 return 意味着 jmp_buf
参数被初始化并且可以被另一个 longjmp
使用。但同样,这还不清楚。在最有限的解释中,as if 子句仅表示由 setjmp
编辑的值 return,而不是调用本身。
由于语义不明确,根据 longjmp
.
将 jmp_buf
对象值视为不确定 return 是正确的
如果一个localjmp_buf
实际上是用寄存器而不是栈内存来表示的,setjmp
或者longjmp
有没有可能导致local[=]的内容13=] 在 setjmp
returns 来自 longjmp
?
建议重复
但是,局部变量的处理方式不同于全局变量。特别是,如果本地 jmp_buf
变量实际上保存在寄存器中而不是内存中,则 longjmp
之后的恢复可能不会呈现可重用的 jmp_buf
变量。
作为一项学术练习,我尝试使用 setjmp
代替 goto
。为了将循环替换保留在函数本地,使用的 jmp_buf
也是一个局部变量。
void foo (int n) {
jmp_buf jb;
volatile int i;
i = setjmp(jb);
if (i < n) {
do_stuff(i);
longjmp(jb, ++i);
}
}
我了解在 setjmp
调用和 longjmp
调用之间修改的非易失性局部变量在 longjmp
之后未指定。但是,我对局部 jmp_buf
变量本身很好奇,特别是在 jmp_buf
变量由寄存器而不是堆栈上的内存表示的情况下。
不清楚 longjmp
本身是否可以被认为是可以修改局部 jmp_buf
变量的东西,以及这是否意味着它的内容在 setjmp
returns 时未指定在调用 longjmp
.
我以为我可以通过将 jb
声明为 volatile
来轻松解决问题,但这触发了警告(我将其视为错误):
... error: passing argument 1 of ‘_setjmp’ discards ‘volatile’ qualifier from pointer target type [-Werror=discarded-qualifiers]
setjmp(jb);
^~
此外,setjmp
的规范并没有说明它是在设置 jmp_buf
之后还是在设置 jmp_buf
之前保存寄存器值。
如果我需要关心它,我可以创建一个 jmp_buf
的可变副本并复制它的内容。但是,如果不需要,我想避免这种情况。
没关系。
在相关说明中,您不需要 i
上的 volatile
,因为它是由 setjmp()
分配给的。
仔细阅读 longjmp()
的手册页和我的 K&R C 副本,jb
的内容仅在您的函数体内无效,这意味着如果有第二次调用 longjmp()
,它将看到 jb
的有效视图。在合理的假设下,有效代码不会在较新的标准版本中变得无效,这在今天仍然适用。
TL;DR 你不需要标记 jmp_buf
volatile 类型的变量。
C11 standard 节 §7.13.2.1 第 3 点指出:
All accessible objects have values, and all other components of the abstract machine have state, as of the time the
longjmp
function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the correspondingsetjmp
macro that do not havevolatile
-qualified type and have been changed between thesetjmp
invocation andlongjmp
call are indeterminate.
您的 jmp_buf
对象在 setjmp(jb)
和 longjmp(jb, ++i)
之间没有变化。调用之间唯一改变的变量是 i
,按照标准建议声明为 volatile
。
所以,为了回答你的问题,longjmp
不能单独“修改本地 jmp_buf
的内容 [以这种方式] 会导致其内容在 [=11 时未定义=] returns”,但是通过其他方式修改两次调用之间的jmp_buf
肯定会造成麻烦。
TL;DR 由于标准不明确,最好把a的值local jmp_buf
在 local longjmp
.
ISO/IEC 9899:2018 §17.13.1.1 ¶2 描述了 setjmp
的行为,而 ¶3 描述了 return.
The
setjmp
macro saves its calling environment in itsjmp_buf
argument for later use by thelongjmp
function....
If the return is from a direct invocation, the
setjmp
macro returns the value zero. If the return is from a call to thelongjmp
function, thesetjmp
macro returns a nonzero value.
我们推断 setjmp
的成功 return 会导致初始化的 jmp_buf
参数。但是,没有提及初始化是否考虑到 jmp_buf
本身具有自动存储持续时间(因此,它本身可以由寄存器而不是内存表示)。
ISO/IEC 9899:2018 §7.13.2.1 ¶3 描述了 longjmp
的行为,措辞与
All accessible objects have values, and all other components of the abstract machine254) have state, as of the time the
longjmp
function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the correspondingsetjmp
macro that do not have volatile-qualified type and have been changed between thesetjmp
invocation andlongjmp
call are indeterminate.
254)This includes, but is not limited to, the floating-point status flags and the state of open files.
不过,between这个词的意思有点难以捉摸。该标准可以明确指定 between 的上下文,表示在 setjmp
完成之后。例如,措辞可以是:
... changed between the
setjmp
return andlongjmp
call are indeterminate.
当前的措辞表明,应该将 setjmp
本身的调用包括在内,作为可能触发不确定条件的东西。
但是,longjmp
的 return 的语义有可能涵盖这个问题。 ISO/IEC 9899:2018 §17.13.2.1 ¶4 状态:
After
longjmp
is completed, thread execution continues as if the corresponding invocation of thesetjmp
macro had just returned the value specified byval
. ...
这句话可以解释为 setjmp
的调用语义是相同的,无论是来自直接调用的 return 还是来自 longjmp
的 return功能。也就是说,setjmp
的 return 意味着 jmp_buf
参数被初始化并且可以被另一个 longjmp
使用。但同样,这还不清楚。在最有限的解释中,as if 子句仅表示由 setjmp
编辑的值 return,而不是调用本身。
由于语义不明确,根据 longjmp
.
jmp_buf
对象值视为不确定 return 是正确的