setjmp.h
setjmp.h이 글은 검증을 위해 추가 인용문이 필요합니다. – · · · · JSTOR (2016년 12월 (이 메시지 및 ) |
C 표준 라이브러리(libc) |
---|
일반적인 토픽 |
기타 헤더 |
setjmp.h는 "비 로컬점프"를 제공하기 위해 C 표준 라이브러리에서 정의된 헤더입니다.즉, 통상의 서브루틴 콜 및 리턴 시퀀스에서 벗어난 제어 플로우입니다.상호 보완적인 기능 및 이 기능을 제공합니다.
의 일반적인 용도setjmp
/longjmp
의 기능을 이용하는 예외 메커니즘의 실장입니다.longjmp
여러 수준의 함수 호출에서도 프로그램 또는 스레드 상태를 재정립합니다.의 사용 빈도가 낮은setjmp
coroutines와 유사한 구문을 작성하는 것입니다.
멤버 함수
인트 setjmp(jmp_buf 부러워하다) | 로컬을 설정합니다.jmp_buf 버퍼링하여 점프용으로 초기화합니다.이[1] 루틴은 프로그램의 호출 환경을 에 의해 지정된 환경 버퍼에 저장합니다.env 나중에 사용하기 위한 의론longjmp 직접 호출에서 반환된 경우setjmp 0 이 반환됩니다.에의 콜로부터의 반환인 경우longjmp ,setjmp 0이 아닌 값을 반환합니다. |
무효 롱점프(jmp_buf 부러워하다, 인트 가치) | 환경 버퍼의 컨텍스트를 복원합니다.env 의 호출에 의해 보호되었다.setjmp 프로그램을[1] 동일한 호출로 실행하는 루틴입니다.호출longjmp 는 정의되어 있지 않습니다.에 의해 지정된 값value 에서 전달되다longjmp 로.setjmp .끝나고longjmp 완료, 프로그램 실행은 마치 대응하는 호출처럼 계속됩니다.setjmp 막 돌아온 참이었어요이 경우,value 에 전달되었다longjmp 0 입니다.setjmp 1을 반환한 것처럼 동작합니다.그렇지 않으면 반환된 것처럼 동작합니다.value . |
setjmp
는, 프로그램 실행의 어느 시점에서 현재의 환경(프로그램 상태)을 플랫폼 고유의 데이터 구조에 보존합니다.jmp_buf
나중에 프로그램 실행 시 사용할 수 있습니다.longjmp
프로그램 상태를 에 의해 저장된 상태로 되돌리다setjmp
안으로jmp_buf
이 프로세스는 프로그램 실행 시점으로 돌아가는 '점프'라고 생각할 수 있습니다.setjmp
환경을 살렸습니다.(외관상) 반환값setjmp
컨트롤이 정상적으로 그 포인트에 도달했는지(제로) 또는 콜에서에 도달했는지 여부를 나타냅니다.longjmp
(제로 이외).이것은 일반적인 관용어로 이어집니다.if( setjmp(x) ){/* handle longjmp(x) */}
.
POSIX.1 에서는, 다음과 같이 지정되어 있지 않습니다.setjmp
그리고.longjmp
차단된 신호의 현재 세트를 저장하고 복원합니다. 프로그램이 신호 처리를 사용하는 경우 POSIX를 사용해야 합니다.sigsetjmp
/siglongjmp
.
멤버 타입
jmp_buf | 다음과 같은 배열 유형struct __jmp_buf_tag[1] 는,[2] 콜 환경의 복원에 필요한 정보를 보관 유지하는데 적합합니다. |
C99의 근거는 다음과 같습니다.jmp_buf
이전 버전과의 호환성을 위해 어레이 타입으로 사용됩니다.기존 코드는jmp_buf
이름별 저장 위치(미포함)&
address-of-operator)를 지정할 수 있습니다.[3]
주의사항 및 제한사항
"비 로컬 goto"가 다음을 통해 실행되는 경우setjmp
/longjmp
C++ 에서는, 통상의 「스택 언와인딩」은 발생하지 않습니다.따라서 필요한 정리 작업도 수행되지 않습니다.여기에는 파일 기술자 닫기, 버퍼 플러시 또는 힙 할당 메모리 해방 등이 포함됩니다.
이 함수가setjmp
반품이라고 불렸기 때문에 더 이상 안전하게 사용할 수 없습니다.longjmp
서신 교환과 함께jmp_buf
물건.이는 함수가 반환되면 스택프레임이 비활성화되기 때문입니다.부르기longjmp
는 스택 포인터를 복원합니다.이것은 함수가 반환되었기 때문에 존재하지 않는 스택프레임의 [4][5]덮어쓰기 또는 파손 가능성을 가리킵니다.
마찬가지로 C99는 다음을 요구하지 않는다.longjmp
현재 스택 프레임을 유지합니다.즉, 호출을 통해 종료된 함수에 뛰어들어longjmp
정의되어 [6]있지 않습니다.단, 대부분의 구현은longjmp
스택 프레임을 그대로 유지하여setjmp
그리고.longjmp
멀티태스킹에 이용되는 기능인 두 개 이상의 기능 사이를 왔다 갔다 하기 위해 사용됩니다.
사용 예
간단한 예
다음 예시는 setjmp의 기본 개념을 나타내고 있습니다.거기.main()
콜first()
그 결과, 콜이 발신됩니다.second()
.그리고나서,second()
다시 뛰어들다main()
건너뛰기first()
가 요구하는 것printf()
.
#실패하다 <stdio.h> #실패하다 < setjmp >h> 정적인 jmp_buf 부프; 무효 둘째() { 인쇄물('세컨드\n"); // 인쇄 롱점프(부프,1); // setjmp가 호출된 곳으로 돌아가 setjmp가 1을 반환하도록 합니다. } 무효 첫번째() { 둘째(); 인쇄물("첫 번째\n"); // 인쇄되지 않음 } 인트 주된() { 한다면 (!setjmp(부프)) 첫번째(); // 실행 시 setjmp가 0을 반환했습니다. 또 다른 // longjmp가 다시 점프하면 setjmp는 1을 반환합니다. 인쇄물(메인\n"); // 인쇄 돌아가다 0; }
실행 시 위의 프로그램은 다음과 같이 출력됩니다.
세컨드 메인
주의해 주세요.first()
서브루틴이 호출됩니다.first
"는 인쇄되지 않습니다."main
" 가 조건문으로 출력됩니다.if (!setjmp(buf))
두 번째로 실행됩니다.
예외 처리
이 예에서는,setjmp
는 다른 언어에서와 같이 예외 처리를 괄호로 묶기 위해 사용됩니다.문의처longjmp
와 유사합니다.throw
예외로 인해 에러 상태를 직접 반환할 수 있습니다.setjmp
다음 코드는 1999년 ISO C 표준 및 단일 UNIX 사양을 호출하여 준수합니다.setjmp
한정된 범위의 컨텍스트:[7]
- 의 조건으로서
if
,switch
또는 반복문 - 위와 같이 싱글과 조합하여
!
또는 정수 상수와의 비교 - 스테이트먼트로서(반환값은 미사용)
이러한 규칙을 따르면 구현에서 환경 버퍼를 쉽게 생성할 수 있으며, 이는 중요한 작업이 [3]될 수 있습니다.보다 일반적인 용도setjmp
는 로컬 변수의 파손 등 정의되지 않은 동작을 일으킬 수 있습니다.컴파일러 및 환경을 준수하여 이러한 사용을 보호하거나 경고할 필요는 없습니다.하지만, 조금 더 세련된 관용구들은 다음과 같다.switch ((exception_type = setjmp(env))) { }
문학과 실무에서 흔히 볼 수 있으며 비교적 휴대성이 우수합니다.상태 버퍼와 함께 추가 변수가 유지되는 간단한 적합 방법론을 다음에 제시합니다.이 변수는 버퍼 자체를 포함하는 구조로 상세하게 설명될 수 있습니다.
보다 현대적인 예에서는 통상적인 "try" 블록이 setjmp로 구현됩니다(다단계 점프를 위한 준비 코드 포함).first
옵션 파라미터를 예외로 하여 longjmp로 "throw"하고 "try" 아래에 있는 "trip" 블록으로 "trip"을 지정합니다.
#실패하다 < setjmp >h> #실패하다 <stdio.h> #실패하다 <stdlib.h> #실패하다 <문자열>h> 정적인 무효 첫번째(); 정적인 무효 둘째(); /* 예외 스택에 파일 범위 정적 변수를 사용하여 * 번역 유닛 내 어디에나 있습니다.*/ 정적인 jmp_buf exception_env; 정적인 인트 exception_type; 인트 주된(무효) { 차* 휘발성의 mem_memblocks = 특수한 순서; 한다면 (setjmp(exception_env)) { // 여기에 도착하면 예외가 있습니다. 인쇄물("첫 번째 실패, 예외 유형: %d\n", exception_type); } 또 다른 { // longjmp를 통해 장애를 알릴 수 있는 코드를 실행합니다. 놓다("먼저 시작"); 첫번째(); mem_memblocks = 마로크(300); // 자원 할당 인쇄물(%s\n", 스트럭시(mem_memblocks, "처음 성공")); // 도달하지 않음 } 공짜(mem_memblocks); // NULL을 free로 전달할 수 있습니다.연산은 실행되지 않습니다. 돌아가다 0; } 정적인 무효 첫번째() { jmp_buf my_env; 놓다("먼저 시작"); // 도달했습니다. 메모리(my_env, exception_env, 크기 my_env); 전환하다 (setjmp(exception_env)) { 사례. 3: // 우리가 여기 도착했을 때 예외가 있었다. 놓다("두 번째 실패, 예외 유형: 3; 유형 1에 다시 매핑"); exception_type = 1; 체납: // 실패 메모리(exception_env, my_env, 크기 exception_env); // 예외 스택 복원 롱점프(exception_env, exception_type); // 예외 처리를 계속합니다. 사례. 0: // 정상, 원하는 작동 놓다("160초"); // 도달했습니다. 둘째(); 놓다("두 번째 성공"); // 도달하지 않음 } 메모리(exception_env, my_env, 크기 exception_env); // 예외 스택 복원 놓다("먼저 시작"); // 도달하지 않음 } 정적인 무효 둘째() { 놓다("160초" ); // 도달했습니다. exception_type = 3; 롱점프(exception_env, exception_type); // 프로그램이 실패했음을 선언합니다. 놓다("160초"); // 도달하지 않음 }
이 프로그램의 출력은 다음과 같습니다.
첫 번째 발신자 입력 첫 번째 발신자 입력 두 번째 발신자 입력 두 번째 발신자 입력 실패, 예외 유형: 3; 유형 1로의 재매핑 실패, 예외 유형: 1
공동 멀티태스킹
C99는 다음을 제공합니다.longjmp
는, 행선지가 발신 기능인 경우, 즉 행선지 스코프가 온전하게 보증되고 있는 경우에만 동작합니다.에 의해 이미 종료된 함수로 이동return
또는longjmp
정의되어 [6]있지 않습니다.단, 대부분의 구현은longjmp
점프를 수행할 때 로컬 변수를 특별히 파괴하지 마십시오.컨텍스트는 로컬 변수가 지워질 때까지 존속하기 때문에 실제로 다음 방법으로 복원할 수 있습니다.setjmp
많은 환경(Really Simple Threads 나 TinyTimber 등)에서 다음과 같은 관용어가 사용됩니다.if(!setjmp(child_env)) longjmp(caller_env);
호출된 함수가 효과적으로 일시정지 및 정지되도록 할 수 있습니다.setjmp
.
이는 스레드 라이브러리에 의해 부정 이용되며 멀티태스킹 기능을 공동으로 제공하기 위해setcontext
또는 기타 파이버 설비.
그 점을 고려하면setjmp
아동 기능은 일반적으로 방해되지 않는 한 작동합니다.setcontext
POSIX의 일부로서 C의 실장에 의해 제공될 필요는 없습니다.이 메커니즘은, 다음의 경우에 휴대할 수 있습니다.setcontext
대체가 실패합니다.
이러한 메커니즘의 여러 스택 중 하나의 오버플로우에는 예외가 생성되지 않으므로 다음을 포함하는 스택을 포함하여 각 컨텍스트에 필요한 공간을 과대 평가하는 것이 중요합니다.main()
정기적인 실행을 중단시킬 수 있는 신호 핸들러를 위한 공간을 포함합니다.할당된 공간을 초과하면 일반적으로 가장 바깥쪽 함수가 먼저 있는 다른 컨텍스트가 손상됩니다.안타깝게도 이러한 프로그래밍 전략을 필요로 하는 시스템도 리소스가 제한된 소규모 시스템인 경우가 많습니다.
#실패하다 < setjmp >h> #실패하다 <stdio.h> jmp_buf 메인 태스크, 자태스크; 무효 call_with_displays(호출)(); 무효 어린아이(); 인트 주된() { 한다면 (!setjmp(메인 태스크)) { call_with_displays(호출)(); // 아이가 돌아오지 않음, 양보 } // 이 "}" 이후에 해당 아이가 처음 산출한 후 실행이 재개됩니다. 하는 동안에 (1) { 인쇄물("부모님\n"); 한다면 (!setjmp(메인 태스크)) 롱점프(자태스크, 1); // 항복 - 이것은 C99에서 정의되어 있지 않습니다. } } 무효 call_with_displays(호출)() { 차 공간[1000]; // 메인 실행에 충분한 공간 확보 공간[999] = 1; // 존재하지 않는 어레이를 최적화하지 않음 어린아이(); } 무효 어린아이() { 하는 동안에 (1) { 인쇄물("자녀 루프 시작"\n"); 한다면 (!setjmp(자태스크)) 롱점프(메인 태스크, 1); // yield - C99에서 childTask를 무효로 합니다. 인쇄물("자녀 루프 끝\n"); 한다면 (!setjmp(자태스크)) 롱점프(메인 태스크, 1); // yield - C99에서 childTask를 무효로 합니다. } /* 돌아오지 마세요.대신 main()을 나타내는 플래그를 설정해야 합니다. 우리에게 양보하는 것을 멈추고 longjmp(mainTask, 1)*/ }
레퍼런스
- ^ a b ISO C는 다음과 같이 기술되어 있습니다.
setjmp
매크로로서 실장할 필요가 있습니다만, POSIX 에서는, 정의되어 있지 않은지 아닌지가 명확하게 기술되어 있습니다.setjmp
매크로 또는 함수입니다. - ^ 이것은 GNU C 라이브러리 버전 2.7에서 사용되는 유형입니다.
- ^ a b C99의 근거, 버전 5.10, 2003년 4월, 섹션 7.13
- ^ CS360 강의 노트 - Setjmp 및 Longjmp
- ^ setjmp(3) Wayback Machine에서 2009-07-26 아카이브 완료
- ^ a b ISO/IEC 9899:1999, 2005, 7.13.2.1:2 및 각주 211
- ^ The Single UNIX Specification, The Open Group 버전 4 : 로컬 이외의 goto의 점프 포인트 설정– System Interfaces Reference,
외부 링크
- The Single UNIX Specification, The Open Group 버전 4 : 로컬 이외의 goto의 점프 포인트 설정– System Interfaces Reference,
- Longjmp 및 Setjmp를 사용하는 C의 예외
- sigsetjmp/siglongjmp(다시)가 있습니까(mingw/MSYS의 이 기능에 대해)