2009-09-08 4 views
20

제 질문은 로컬 변수에 관한 setjmp/longjmp의 동작을 목표로합니다.setjmp/longjmp 및 로컬 변수

예제 코드 : setjmp는의

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(); 
} 

문서는/longjmp를 말한다 :

"모든 접근 객체(), 호출 된 시간 longjmp를 기준으로 값이 개체의 값 것을 제외하고 이 volatile 지정 유형이없고 setjmp() 호출과 longjmp() 호출 사이에 이 변경된 해당 setjmp() 호출을 포함하는 함수에 로컬 인 자동 저장 기간은 불확정합니다. "

나는 두 가지 해석은 다음을 참조하십시오

intepretation1 :

지역 변수가 모두

  • 비 휘발성 및
변경되는 것을 제외하고, 복원

침입 2 :

로컬 변수

  • 제외 복원 비 휘발성이며
  • longjmp를 V1 만이 정의 된 후 interpretation1 따르면

변경되는 이러한 것들. v2, v3, v4가 정의됩니다. longjmp 이후의 해석 2에 따르면 v4 만 정의됩니다. v1, v2, v3은 정의되지 않습니다.

어느 것이 옳은가요?

BTW : 모든 컴파일러에 유효한 일반 ("휴대용") 대답이 필요합니다. 즉, 특정 컴파일러로 시도해도 도움이되지 않습니다.

+0

구현 참고 사항 : 변경되거나 비 휘발성 인 변수는 longjmp와 동일하거나 코드 생성에 따라 setjmp 당시의 상태로 복원 될 수 있습니다. 따라서 '불확정'. 그래서, 만약 그들이 * 변경되지 않았다면,이 두 값은 동일하고 따라서 변경되지 않은 변수는 안전합니다. – greggo

답변

10

해석 1이 정확합니다. 해석 2가 의도 된 경우 원본 텍스트는 "및"대신 "또는"을 사용했을 것입니다.

26

setjmp/longjmp는 처음 통과 할 때 레지스터 (스택 및 코드 포인터 등 포함)를 저장하고 점프 할 때이를 복원하여 구현됩니다.

자동 가 아닌 레지스터 스택에 저장 될 수있는 '휘발성'없는 변수 (일명 "로컬", 할당 스택).

이러한 상황에서 longjmp는 setjmp()가 처음 호출 된 시점에서 이러한 레지스터 변수를 해당 값으로 복원합니다.

또한 특히 현명한 컴파일러는 다른 변수의 상태에서 유추 할 수있는 변수를 피하고 필요할 때 계산할 수 있습니다.가변 자동하지만 레지스터가 할당되어 있지 않은 경우에는, 그것이 setjmp는 상기 longjmp를 사이 코드에 의해 변경 될 수

..

휘발성

명시 레지스터에 변수를 저장하지 컴파일러 말하고 .

변수가 휘발성이라고 명시하지 않으면 setjmp/longjmp 사이에서 변수를 변경하면 컴파일러의 선택에 따라 값이 달라 지므로 의존하지 않아도됩니다 ('불확정').

+0

그리고 역으로, 'register'*로 선언 된 자동 변수는 레지스터에 저장 될 수 있지만 컴파일러는 힌트를 무시할 수 있으므로 복원되지 않을 수도 있습니다. – Michael

+0

@Michael 실제로 "복원 된"것이라는 보장조차 없습니다. '보통'의 경우는 변수가 longjmp를 결과로 가져온 함수를 호출하기 전에 변수에 값을 갖게한다는 것입니다. 위에서 논의 된 것처럼 몇몇 경우에는 setjmp/longjmp에 의해 수행되는 모든 호출 저장 레지스터의 블라인드 복원으로 'clobbered'할 수 있습니다. 실제로 이것은 clobbered 경우 'setjmp'값으로 복원되지만 언어에서는 마지막으로 설정 한 값보다 불확정하다는 것을 나타냅니다. – greggo