2009-09-08 94 views
20

我的问题是针对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:

局部变量被恢复,除了

  • 那些非易失性和
  • 那些改变

根据interpretation1后的longjmp只有V1是未定义的。 v2,v3,v4被定义。 根据longjmp之后的解释2,只定义了v4。 v1,v2,v3未定义。

哪一个是正确的?

顺便说一句:我需要一个适用于所有编译器的通用(“便携式”)答案,即尝试使用一个特定的编译器没有帮助。

+0

实现注意:变量和非易失性的变量可能与longjmp时相同,或者可能会恢复到setjmp时的值,具体取决于代码生成。因此'不确定'。所以,如果他们不*改变,这两个值是相同的,这就是为什么不变的变量是安全的。 – greggo 2012-04-13 21:27:11

回答

10

解释1是正确的。如果意图解释2,则原文将使用“”或“”,而不是“和”。

26

setjmp/longjmp通过首次传递时保存寄存器(包括堆栈和代码指针等)并在跳转时恢复它们来实现。

自动(又名“本地”,堆栈分配的),其不是“挥发性” 可以存储在寄存器中,而不是在堆栈上的变量。

在这些情况下,longjmp会在首次调用setjmp()时将这些寄存器变量恢复为它们的值。

此外,一个特别聪明的编译器可能会避免可以从另一个变量的状态推断出变量,并根据需要计算它们。

然而,如果变量是自动的,但尚未被分配寄存器,它可以由setjmp和所述longjmp的代码之间改变..

挥发性明确地告诉编译器不给变量存储在寄存器。所以除非你明确地说变量是volatile的,否则如果你改变了setjmp/longjmp之间的变量,它的值将取决于编译器的选择,因此你不应该依赖('indeterminate')。

+0

我相反地猜测,声明为'register'*的自动变量可能被存储在寄存器中,但编译器可能会忽略该提示,所以这不能保证它们也能被恢复。 – Michael 2015-04-17 17:33:17

+0

@迈克尔其实甚至没有保证任何东西都“恢复”。 '正常'的情况是变量将具有它们的价值,然后再调用导致longjmp的任何函数。在上面讨论的某些情况下,它们可能会通过盲目恢复由setjmp/longjmp完成的所有调用保存的寄存器来“破坏”。在实践中,这意味着,如果受到破坏,它们可能会恢复到'setjmp'值,但是该语言只说明它们是不确定的,而不是你最后设定的值。 – greggo 2016-11-04 15:07:23