我的问题针对的是 setjmp/longjmp 关于局部变量的行为。
示例代码:
jmp_buf env;
void abc()
{
int error;
...
if(error)
longjmp(env);
}
void xyz() {
int v1; // non-volatile; changed between setjmp and longjmp
int v2; // non-volatile; not changed between setjmp and longjmp
volatile int v3; // volatile; changed between setjmp and longjmp
volatile int v4; // volatile; not changed between setjmp and longjmp
...
if(setjmp(env)) {
// error handling
...
return;
}
v1++; // change v1
v3++; // change v3
abc();
}
int main(...) {
xyz();
}
setjmp/longjmp 的文档说:
“所有可访问的对象在调用 longjmp() 时都具有值, 除了自动存储持续时间的对象的值 对于包含相应调用的函数是本地的 setjmp() 不具有 volatile 限定类型且已更改 setjmp() 调用和 longjmp() 调用之间是不确定的。”
我看到以下两种可能的解释:
解释1:
局部变量被恢复,除了两者都是的
- 非 volatile 和
- 改变了
解释2:
局部变量被恢复,除了
- 那些是非 volatile 的和
- 改变的
根据 longjmp 之后的解释 1 只有 v1 是未定义的。 v2、v3、v4 已定义。 根据 longjmp 之后的解释 2,仅定义了 v4。 v1、v2、v3 未定义。
哪个是对的?
顺便说一句:我需要一个对所有编译器都有效的通用(“可移植”)答案,即尝试使用一个特定的编译器没有帮助。
最佳答案
setjmp/longjmp的实现方式是在第一次通过时保存寄存器(包括栈和代码指针等),跳转时恢复。
非“ volatile ”的自动(也称为“本地”、堆栈分配)变量可能存储在寄存器中而不是堆栈中。
在这些情况下,longjmp 会将这些寄存器变量恢复为它们在首次调用 setjmp() 时的值。
此外,一个特别聪明的编译器可能会避免使用可以从另一个变量的状态推断出的变量,并根据需要计算它们。
但是,如果变量是自动的但没有分配寄存器,它可能会被 setjmp 和 longjmp 之间的代码改变..
Volatile 明确告诉编译器不要将变量存储在寄存器中。
因此,除非您明确声明一个变量是易变的,否则如果您在 setjmp/longjmp 之间更改变量,其值将取决于编译器所做的选择,因此您不应该依赖任何东西(“不确定”)。
关于c - setjmp/longjmp 和局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1393443/