2009-09-08 92 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