구조화된 예외
#include <stdio.h>
#include <Windows.h>
int main()
{
int n = 0
int s = 10 / 0; // (컴파일러가 똑똑해 져서) 컴파일 에러 발생
}
int main()
{
int n = 0
int s = 10 / n; // 런타임에 에러
}
런타임 에러가 발생하는 기전은
기게어 코드에서 문제발생 -> CPU에 통보 -> Windows OS에 통보 -> IDE에 Exception을 전달
- C++에서 제공하는 예외가 아니라 Windows OS에서 제공하는 예외이다.
__try{} __except{}
를 이용해 예외를 잡아보자
int main()
{
int n = 0
// 아래와 같은 방식으로 Windows OS exception을 잡을 수 있다.
__try
{
int s = 10 / n;
}
__except(1)
{
// 왜 죽었는지 확인방법
printf("exception : %x\n", GetExceptionCode());
}
}
__except()
는 에 들어갈수 있는 매개변수는 세 가지이다.- EXCEPTION_EXECUTE_HANDER(1) : 일반적 예외
- EXCEPTION_CONTINUE_SEARCH(2) : except를 받았지만 일단은 처리하지 않고 다름 try를 찾아라
- EXCEPTION_CONTINUE_EXECUTION(-1) : 다시 try문을 시도해라
int n = 0
DWORD Filter(DWORD code)
{
if(code == EXCEPTION_INT_DEVIDE_BY_ZERO)
{
printf("divide by zero");
n = 5;
return EXCEPTION_CONTINUE_EXECUTION; // 재시도 해보시오
}
printf("other exception\n");
return EXCEPTION_EXECUTE_HANDER;
}
int main()
{
__try
{
int s = 10 / n;
}
__except(Filter(GetExceptionCode()))
{
// 참고로 GetExceptionCode()는 except내부에서만 호출이 가능하지 다른 함수에서 호출이 불가능
printf("exception : %x\n", GetExceptionCode());
}
}
어느 레지스터에 발생했는지 확인 방법
예외 발생시 스택에 예외 정보가 추가된다.
GetExceptionInformation()
을 통해 알 수있다.
단, GetExceptionInformation()
은 __exceptp(/*여기*/)
에서만 호출이가능하다
다른곳에서 호출 시 스택이 모두 지워진다.
#include <stdio.h>
#include <Windows.h>
DWORD Filter(EXCEPTION_POINTERS* ep)
{
DWORD code = ep->ExceptionRecord->ExceptionCode;
void* addr = ep->ExceptionRecord->ExceptionAddress;
// ep->ContextRecord->Eip;
return EXCEPTION_EXECUTE_HANDER;
}
int main()
{
int n = 0;
__try
{
int s = 10 / n;
}
__except(Filter(GetExceptionInformation()))
// GetExceptionInformation()는 __except의 매개변수로만 들어갈 수 있다는 점을 기억.
{
printf("exception : %x\n", GetExceptionCode());
}
}
C++ 예외
class AAA
{
public:
~AAA() {}
};
int main()
{
__try
{
// C++ 객체가 있으면 exception을 못잡음.
// C++ 에서는 못쓴다는 말. 이후에 어떻게 사용될지 알려준다
AAA aaa; // 디버그 에러
char* p = 0;
p = 0; // Exception
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("exceptin\n");
}
}