setjmp / longjmp和局部变量
我的问题针对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()调用之间更改的是不确定的。“
我看到以下两种可能的解释:
intepretation1:
除了两者之外,还会恢复局部变量
- 非挥发性的
- 变
intepretation2:
除了之外,还会恢复局部变量
- 那些非挥发性的
- 那些改变了
根据解释1,在longjmp之后只有v1是未定义的。 定义了v2,v3,v4。 根据解释2,在longjmp之后只定义了v4。 v1,v2,v3未定义。
哪一个是对的?
顺便说一句:我需要一个对所有编译器都有效的通用(“便携式”)答案,即尝试使用一个特定的编译器没有帮助。
解释1是正确的。 如果打算解释2,原始文本将使用“ 或更改”而不是“和”。
setjmp / longjmp是通过在第一次传递时保存寄存器(包括堆栈和代码指针等)并在跳转时恢复它们来实现的。
不是“易失性”的自动(也称为“本地”,堆栈分配)变量可以存储在寄存器中而不是存储在堆栈中。
在这些情况下,longjmp会将这些寄存器变量恢复为首次调用setjmp()时的值。
此外,一个特别聪明的编译器可能会避免可以从另一个变量的状态推断出的变量,并根据需要计算它们。
但是,如果变量是自动的但没有分配寄存器,则可以通过setjmp和longjmp之间的代码进行更改。
Volatile明确告诉编译器不要将变量存储在寄存器中。
因此,除非您明确说变量是volatile,否则如果您更改了setjmp / longjmp之间的变量,它的值将取决于编译器所做的选择,因此您不应该依赖它(’indeterminate’)。