티스토리 뷰

C | C++

비지역적 점프

야라바 2018. 8. 4. 14:34
728x90

☞ setjmp, longjmp

<setjmp.h>

int setjmp(jmp_buf state);
void longjmp(jmp_buf state, int value);

C언어에서는 함수 내부를 지역(Local) 범위, 함수 외부를 전역(Global) 범위라고 합니다. 통상 return 구문을 통해서 하나의 지역 범위를 벗어 납니다. 함수 내부의 지역 범위에서도 for, do ~ while, while, switch 구문 내부를 더 세밀한 지역 범위라고 부를 수 있는데 이러한 지역 범위는 통상 break 구문을 통해서 벗어납니다. 문제는 이러한 함수 호출이 누적되거나 내부 지역 범위의 내포(Nested) 레벨이 깊어진 상태에서 특정한 시점으로 되돌아 가려면 정상적인 흐름으로는 break 내지 return 구문을 모두 거쳐야 된다는 것입니다. 이러한 복잡한 흐름 이동 문제를 단번에 해결해 주는 것이 setjmp, longjmp를 이용한 비지역적 점프입니다. 물론 함수 호출 및 내부 지역 이동 과정에서 메모리 할당이나 파일 오픈이 있었던 경우라면 당연히 정상적인 메모리 해제나 파일 닫기 과정 거쳐야 겠지만 이러한 요소로 인한 문제점이나 위험성이 없거나 대처할 수 있다면 비지역적 점프를 활용할만 합니다.



☞ 예제1

static jmp_buf csql_Jmp_buf;
......
static void csql_pipe_handler (int sig_no)
{
    longjmp (csql_Jmp_buf, 1);
}
......    
static void display_buffer (void)
{
    int l = 1;
    FILE *pf;
    void (*csql_pipe_save) (int);

    csql_pipe_save = os_set_signal_handler (SIGPIPE, &csql_pipe_handler);
    if (setjmp (csql_Jmp_buf) == 0)
    {
        char *edit_contents, *p;
        pf = csql_popen (csql_Pager_cmd, csql_Output_fp);

        edit_contents = csql_edit_contents_get ();

        putc ('\n', pf);
        while (edit_contents != NULL && *edit_contents != '\0')
        {
            fprintf (pf, "%4d  ", l++);
            p = strchr (edit_contents, '\n');
            if (p)
            {
                fwrite (edit_contents, 1, p - edit_contents, pf);
                edit_contents = p + 1;
            }
            else
            {
                fwrite (edit_contents, 1, strlen (edit_contents), pf);
                edit_contents = NULL;
            }
            fprintf (pf, "\n");
        }
        putc ('\n', pf);

        csql_pclose (pf, csql_Output_fp);
    }
    (void) os_set_signal_handler (SIGPIPE, csql_pipe_save);
}

위의 큐브리드 DBMS 코드 예제를 보면 if 구문 내부에서 리턴값이 0인가를 묻고 있는 setjmp() 문장이 있는데 이 함수를 호출하는 지점이 바로 비지역적 점프를 위해서 돌아올 지점을 저장하는 위치이기도 할 뿐만아니라 longjmp를 통해서 실제로 돌아오는 위치이기도 합니다. setjmp()가 jmp_buf 오브젝트를 이용해서 돌아올 위치를 저장하는 시점에서는 0을 리턴하지만 프로그램 수행중에 비지역적 점프가 호출된 경우라면 0이 아닌 값이 리턴됩니다. longjmp()의 두번째 인수인 value에 지정한 값이 리턴되지만 longjmp의 value 인수 값을 0으로 지정해도 강제로 setjmp()에서는 1이 리턴됩니다. 위의 예제에서는 프로그램 실행 과정중에 비지역적 점프가 호출되면 if (setjmp (csql_Jmp_buf)...에서 0이 아닌 값으로 리턴되므로 if()문 바깥으로 흐름이 이어집니다.




728x90

'C | C++' 카테고리의 다른 글

시그널 다루기  (0) 2018.08.04
시그널의 종류와 핸들러  (0) 2018.08.04
알람과 sleep  (0) 2018.06.29
문자열의 일시 변환  (0) 2018.06.29
일시의 문자열 변환  (0) 2018.06.29