때때로 당신의 프로그램이 호출한 함수의 깊게 내포된 곳에서 평소와는 다른 상황을 검출할 때, 당신은 제어수준의 밖으로 즉시 반환이 가능하게
되는 것이 좋을 것이다. 이 절은 그와같은 비-지역 탈출의 상황에서
어떻게 setjmp 와 longjmp를 사용할 수 있는지를 설명한다.
비-지역 탈출이 유용할 수 있는 상황에 대한 예제로서, 프롬프트 상에서 명령문으로 실행하는 "메인 루프"를 가진, 즉 상호 작용하는 프로그램이 있다고 가정하자. 그리고 "read"라는 명령문으로는 파일로부터 입력을 읽어서, 그것이 처리되는 동안 입력의 어휘와 구문을 분석한다고 가정하자. 그때 만일 저-수준 입력 에러가 검출되면, 어휘와 구문분석 각각을 만들고, 내포된 호출에 의해 검출된 에러상황을 명백하게 취급하는 모든 처리상황을 만들기보다는 "메인 루프"로 즉시 반환 가능하도록 하는 것이 유용할 것이다. ( 다른 한편으로, 만일 파일들을 닫거나, 버퍼나 다른 데이터 구조체를 해제하는 등의 그와같은 exit의 상황일 때 그들 상황에서 그들에게 할당된 실제적인 양을 소거한다면_보통 반환을 하고 그 자체가 소거되는 것이 더 적당할 수 있다, 왜냐하면 비-지역 탈출은 방해되는 상황들을 무시하고 그들에 연관된 전체 코드를 소거하기 때문이다. 선택적으로 당신은 "메인 루프"의 뒤나 또는 앞에서 명백하게 소거를 할 수 있다. )
어떤 방법에서, 비-지역 탈출은 함수로부터 반환을 하는 `return' 구문을 사용하는 것과 유사하다. 그러나 `return'은 오직 단일하게 호출된 함수로부터 빠져나와서 그것이 호출되었던 지점의 뒤로 호출을 넘기지만, 비-지역 탈출은 내포된 함수 호출의 여러 단계를 빠져나올 수 있다.
당신은 setjmp 함수를 호출해서 비-지역 탈출을 위한 반환지점을 확인하라. 이 함수는 object의 타입 jmp_buf안에 실행환경에 대한 정보를 저장한다. setjmp의 호출 후에도 프로그램의 실행은 정상적으로 계속되지만, 만일 한 exit가 그것에 부합되는 jmp_buf 오브젝트를 인수로 하여 longjmp를 호출함으로써 이 반환 지점보다 나중에 만들어졌다면 제어는 setjmp가 호출되었던 그 지점의 뒤로 넘겨진다. setjmp로 부터의 반환값은, 보통의 반환과 longjmp를 호출함으로 해서 만들어진 반환과의 구별하기 위해 사용되므로, setjmp는 보통 `if'문안에 나타난다.
위에 설명된 예제 프로그램이 어떻게 만들어지는지를 보여준다.
여기에서는 비-지역 분기를 수행하기 위해 사용되는 함수들과 데이터 구조체에 대해서 설명한다. 이들 도구들은 `setjmp. h'에 선언되어 있다.
데이터 타입 : jmp__buf
매크로 : int setjmp (jmp_buf state)
함수 : void longjmp (jmp_buf state, int value)
setjmp와 longjmp의 사용에는 많이 모호하지만 중요한 제한들이 있다. 이들 제한의 대부분은 비-지역 분기가 C 컴파일 상에서 상당한 양의 신비한 힘(?)을 요구했고 이상한 방법으로 언어의 다른 부분들과 함께 영향을 끼칠 수 있기 때문에 발생한다.
setjmp함수는 함수정의가 없는 매크로이다, 그래서 당신은 `#undef를 사용하거나 또는 그것의 주소를 취하려 할 수가 없다. 그것에 더하여, setjmp를 호출하는 것은 오직 다음과 같은 경우에만 안전하다.
반환지점은 그들을 만들기 위해서 setjmp를 호출했던 그 함수가 계속 작동하고 있을때만 유용하다. 만일 당신이 이미 반환되어진 함수에서 만들었던 반환지점으로 longjmp를 호출하면, 예측할 수 없고 불행한 일들이 발생될 것이다.
당신은 longjmp의 인수로써 0이 아닌 값을 사용수도 있다. longjmp는 setjmp로부터의 반환값인 0 인수를 되돌려주기를 거부하므로, 갑자기 발생하는 실수들에 대항한 안전망으로써의 역할을 할 수도 있지만 좋은 프로그래밍 스타일은 아니다.
당신이 비-지역 분기를 수행할 때, 검색 가능한 오브젝트들은 longjmp가 호출되었을 때 그들이 가졌던 값이 무엇이든지 일반적으로 계속 유지한다. 그러나 자동 지역변수의 경우에는 setjmp가 호출된 이후에 변경된다. 즉 그들을 휘발성으로 선언하지만 않으면 그들은 변경되지 않는다.
BSD 유닉스 시스템에서, setjmp와 longjmp는 블록된 신호들을 저장하고 반환한다; 21. 7절 [Blocking Signals] 참조. 그렇지만, POSIX. 1 표준은 setjmp와 longjmp가 블록된 신호들을 변경하지 않을 것을 요구하고, BSD처럼 행동하기 위한 함수들(sigsetjmp와siglongjmp) 두 개를 부가적으로 제공한다.
GNU 라이브러리에서 setjmp와 longjmp의 행동은 테스트 매크로에 의해 제어된다; 1. 3. 4절 [Feature Test Macros] 참조. GNU 시스템에서 디폴트로 사용하는 것은 BSD가 아니라 POSIX. 1 이다. 이 절에 있는 도구들은 헤더파일 `setjmp. h'에 선언되어 있다.
데이터 타입 : sigjmp__buf
함수 : int sigsetjmp (sigjmp_buf state, int savesigs)
함수 : void siglingjmp (sigjmp_buf state, int value)
목차 이전 : 19. 지역과 세계화 다음 : 21. 시그널 처리