setjmp.h

setjmp.h

setjmp.h는 " 로컬점프"를 제공하기 위해 C 표준 라이브러리에서 정의된 헤더입니다.즉, 통상의 서브루틴 콜 및 리턴 시퀀스에서 벗어난 제어 플로우입니다.상호 보완적인 기능 및 이 기능을 제공합니다.

의 일반적인 용도setjmp/longjmp기능을 이용하는 예외 메커니즘의 실장입니다.longjmp여러 수준의 함수 호출에서도 프로그램 또는 스레드 상태를 재정립합니다.의 사용 빈도가 낮은setjmpcoroutines와 유사한 구문을 작성하는 것입니다.

멤버 함수

인트 setjmp(jmp_buf 부러워하다) 
로컬을 설정합니다.jmp_buf버퍼링하여 점프용으로 초기화합니다.[1] 루틴은 프로그램의 호출 환경을 에 의해 지정된 환경 버퍼에 저장합니다.env나중에 사용하기 위한 의론longjmp직접 호출에서 반환된 경우setjmp0 이 반환됩니다.에의 콜로부터의 반환인 경우longjmp,setjmp0이 아닌 값을 반환합니다.
무효 롱점프(jmp_buf 부러워하다, 인트 가치) 
환경 버퍼의 컨텍스트를 복원합니다.env의 호출에 의해 보호되었다.setjmp프로그램을[1] 동일한 호출로 실행하는 루틴입니다.호출longjmp는 정의되어 있지 않습니다.에 의해 지정된 값value에서 전달되다longjmp로.setjmp.끝나고longjmp완료, 프로그램 실행은 마치 대응하는 호출처럼 계속됩니다.setjmp막 돌아온 참이었어요이 경우,value에 전달되었다longjmp0 입니다.setjmp1을 반환한 것처럼 동작합니다.그렇지 않으면 반환된 것처럼 동작합니다.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/longjmpC++ 에서는, 통상의 「스택 언와인딩」은 발생하지 않습니다.따라서 필요한 정리 작업도 수행되지 않습니다.여기에는 파일 기술자 닫기, 버퍼 플러시 또는 힙 할당 메모리 해방 등이 포함됩니다.

이 함수가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아동 기능은 일반적으로 방해되지 않는 한 작동합니다.setcontextPOSIX의 일부로서 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)*/ } 

레퍼런스

  1. ^ a b ISO C는 다음과 같이 기술되어 있습니다.setjmp매크로로서 실장할 필요가 있습니다만, POSIX 에서는, 정의되어 있지 않은지 아닌지가 명확하게 기술되어 있습니다.setjmp매크로 또는 함수입니다.
  2. ^ 이것은 GNU C 라이브러리 버전 2.7에서 사용되는 유형입니다.
  3. ^ a b C99의 근거, 버전 5.10, 2003년 4월, 섹션 7.13
  4. ^ CS360 강의 노트 - Setjmp 및 Longjmp
  5. ^ setjmp(3) Wayback Machine에서 2009-07-26 아카이브 완료
  6. ^ a b ISO/IEC 9899:1999, 2005, 7.13.2.1:2 및 각주 211
  7. ^ setjmp: 로컬 이외의 goto의 점프 포인트 설정– System Interfaces Reference, The Single UNIX Specification, The Open Group 버전 4

외부 링크