LISTORY
[윈도우즈 시스템 프로그래밍] 예외 핸들러 본문
뇌를 자극하는 윈도우즈 시스템 프로그래밍 책 관련 유투브 강의 정리이다.
이번 시간에 정리할 내용은 예외 핸들러이다.
YouTube 주소 : 예외 핸들러(Exception Handler)
예외 핸들러(Exception Handler)
⊙ 예외 핸들러와 필터
__try, __except 블럭이 있다.
이 두개는 이어서 등장해야 한다. 있는 위치는 다르지만 하나의 구문으로 이해해야한다.
__try 블럭에서 발생한 예외는 그 뒤에 나오는 __except에서 처리하겠다고 선언한 것이다.
그런데 그 예외를 처리하는 방식은 크게 세가지로 나뉘어진다. 이걸 필터라고 부른다.
⊙ 예외 처리 필터
- EXCEPTION_EXECUTE_HANDLER
- EXCEPTION_CONTINUE_EXECUTION
- EXCEPTION_CONTINUE_SEARCH
이 필터가 위치하는 위치가 __except 괄호 부분이다.
언뜻 보면 __except에 인자로 전달하는 것처럼 보이지만, 인자로 전달하는 것은 아니고 __except의 인자전달의 위치에 예외처리 방식을 열거하는 것이다.
여기엔 예외 처리 필터 중 하나만 올 수 있다.
예를 들어 보자. 예외가 하나 발생했다.
그럼 실행이 윈도우즈에 의해 __except 블록으로 자동으로 옮겨진다(SEH 매커니즘)
그럼 가장 먼저 하는 것이 예외처리 방식이 무엇인지 확인하게 된다(이 또한 SEH 매커니즘)
그 방식, 즉 필터에 맞게 예외 처리가 진행된다.
예외가 처리되었다? __except 블럭에서 말하는 방식되로 처리되었다.
1. EXCEPTION_EXECUTE_HANDLER
p라는 포인터에 NULL을 대입시켰다. 오타가 발생했는데, 여기는 int *p이다. 즉, 이는 예외를 발생시킨다.
그럼 실행은 자동으로 __except 블럭으로 옮겨지고, 어떻게 처리할지 쳐다본다.
필터가 EXCEPTION_EXECUTE_HANDLER 이므로, 이에 언급하는 방식대로 처리되어야 한다.
EXCEPTION_EXECUTE_HANDLER 방식은 일단, 예외를 except 블럭 안에서 처리한다.
실행이 된 뒤, 예외가 발생된 지점으로 돌아가지 않고 예외가 발생된 시점부터 시작해서 그 나머지 try 블럭의 코드를 건너뛴다.
즉, 예외가 발생한 블럭의 코드는 모두 건너뛰고 그 다음 코드가 실행된다.
▶ 사례
case DIV: 코드 부분에서 예외가 생겼다고 가정해보자.
그럼 _tprintf 문을 실행하는 것이 의미가 없어진다.
그래서 만일 이 부분에 문제가 생긴다면 __except 부분에서 필터를 인지하고 블럭안에 있는 코드를 실행한다.
여기선 출력문을 썼지만 가급적으로 예외를 처리하는 코드를 넣는 것이 좋다.
그 후, 다시 __try 블럭으로 돌아가지 않고 다음 코드들을 실행한다.
⊙ 처리되지 않은 예외의 이동
그림에 써 있는 대로 int a에는 10, int b에 0이 들어갔다면, 예외가 발생한다.
근데 Divide() 함수 부분은 __try 영역으로 감싸지지 않았다.
그럼 이 코드를 감싸고 있는 함수가 전부 반환이 된다.
다시 말해보겠다.
_tmain 함수가 호출되고 _tmain 이 Calculator 함수를 호출한다.
또 Calculator 함수가 divide 함수를 호출했다. 즉, 그 순서대로 Stack에 쌓였다.
이 Divide 함수에 예외가 발생했고, 예외처리를 못했을 경우, 이 Stack이 반환되어 버린다.
그럼 다시 호출된 곳으로 돌아온다. 예외가 처리되지 않은 것이다.
그래서 이 돌아온 부분에서 예외를 처리할 방법을 찾는데, 이 부분은 __try로 묶여 있다.
그래서 여기서 예외를 처리할 수 있다.
하지만 가급적으로 예외는 발생한 위치해서 처리해주는 것이 좋다.
만일 여기에도 __except블럭이 없었다면 main으로 넘어갔을 것이다. main도 처리할 방법이 없다면 이는 운영체제로 넘어간다.
그럼 운영체제는 프로그램을 종료시켜 버린다.
⊙ 예외를 구분하는 방법
▶ GetExceptionCode
어떤 예외가 발생했는지 구분하고 싶을 수도 있다.
예외 A, B, C가 있다. 예외는 각각의 상황으로 인해 발생할 수 있다.
그런데 각기 예외를 처리하는 방식은 다르다. 따라서 __except블럭은 예외가 왜 발생했는지 알 수 있어야 한다.
그를 위해 제공되는 함수가 GetExceptionCode()이다. 이 함수에서 리턴되는 값은 왜 오류가 발생되었는지 알게 해준다.
이는 예외가 발생이 되야 의미가 있는 함수이므로 __except 블럭 내부나 예외필터 표현식 지정 위치 안에서만 호출할 수 있도록 제약되고 있다.
반환값은 다양하게 반환되므로 MSDN을 참조하는 것이 좋다.
2. EXCEPTION_CONTINUE_EXECUTION
위 코드로 설명해보겠다.
앞서 상황과 마찬가지로 num2에 0이 들어오면 예외가 발생이 된다.
그래서 이 부분을 try와 except로 묶고 있다.
근데 여기서 num2만 다시 값을 받고 싶을 경우가 있다. 그럴 경우에 EXCEPTION_CONTINUE_EXECUTION 를 사용한다.
EXCEPTION_CONTINUE_EXECUTION 는 예외를 처리한 뒤, 예외가 발생된 지점으로 다시 돌아간다.
근데 필터가 와야하는데 필터가 오지 않고 있다.
FilterFunction은 우리가 정의한 함수이고, 그 인자를 GetExceptionCode()로 얻게되는 값으로 하겠다고 명시해두었다.
우리가 정의한 FilterFunction 함수를 살펴보겠다.
여기서 0으로 인해 예외가 발생했으므로, EXCEPTION_INT_DIVIDE_BY_ZERO case가 실행된다.
코드를 보면 num 값을 다시 전달받고, 문제가 생긴 지점으로 다시 돌아갈 수 있도록 EXCEPTION_CONTINUE_EXECUTION 를 반환한다.
3. EXCEPTION_CONTINUE_SEARCH
이 필터는 잘 사용되지도 않고, 사용하기 권하지도 않는 필터이다.
이는 예외가 발생한 지점과, 예외를 처리하는 지점을 다르게 하고 싶을 때 사용한다.
'IT > 윈도우 프로그래밍' 카테고리의 다른 글
[윈도우즈 시스템 프로그래밍] 파일 I/O와 디렉터리 컨트롤(2) (0) | 2018.10.27 |
---|---|
[윈도우즈 시스템 프로그래밍] 파일 I/O와 디렉터리 컨트롤 (0) | 2018.10.26 |
[윈도우즈 시스템 프로그래밍] 구조적 예외처리(SEH) 기법(2) (0) | 2018.10.20 |
[윈도우즈 시스템 프로그래밍] 구조적 예외처리(SEH) 기법 (0) | 2018.10.20 |
[윈도우즈 시스템 프로그래밍] 가상 메모리(2) (0) | 2018.10.14 |