∇ 프로그래밍 소품 및 팁

 ▼ Assertion catch하기

C++

N/A

외부 라이브러리가 release 모드로 된 것이 아니라서 예상치 못한 assertion을 만나는 경우가 있다. 그렇다고 외부 라이브러리의 소스를 재컴파일 할수 있는 상황이 아니라면 사태는 더욱 심각해진다. VC++이라면 표준 C++ 형식이 아닌 자체적인 예외 처리 기법을 이용해 해결할 수 있겠지만 그 코드가 VC++뿐만 아니라 다른 플랫폼에서도 구동되어야 하는 것이라면 표준 C++ 문법 이외에는 사용해서는 안된다.

실제로 이런 일을 만나게 되었고 그때 내가 작성한 코드는 다음과 같다.

    01: ///////////////////////////////////////////////////////
    02: // HEADER
    03:
    04: #include <csetjmp>
    05: #include <csignal>
    06: #include <cassert>
    07: #include <cstdio>
    08:
    09: #define ASSERT_TRY if (setjmp(g_env) == 0)
    10: #define ASSERT_CATCH else
    11: #define USE_ASSERT_TRY signal(SIGABRT, AbortHandler);
    12:
    13: ///////////////////////////////////////////////////////
    14: // IMPLEMENTAION
    15:
    16: jmp_buf g_env;
    17:
    18: #if defined(WIN32)
    19: #define CDECL __cdecl
    20: #else
    21: #define CDECL
    22: #endif
    23:
    24: void CDECL AbortHandler(int num)
    25: {
    26:     USE_ASSERT_TRY
    27:     longjmp(g_env, 1);
    28: }
    29:
    30: ///////////////////////////////////////////////////////
    31: // TEST CASE
    32:
    33: int TestFunction(int data)
    34: {
    35:     assert(data != 50);
    36:     return data;
    37: }
    38:
    39: void AssertionTest(void)
    40: {
    41:     int sum = 0;
    42:
    43:     for (int i = 1; i <= 100; i++)
    44:     {
    45:         ASSERT_TRY
    46:         {
    47:             sum += TestFunction(i);
    48:         }
    49:         ASSERT_CATCH
    50:         {
    51:             printf("i = %d일 때 assertion 발생\n", i);
    52:         }
    53:     }
    54:
    55:     printf("\nsum = %d\n", sum);
    56: }
    57:
    58: int main(void)
    59: {
    60:     USE_ASSERT_TRY
    61:
    62:     AssertionTest();
    63:
    64:     return 0;
    65: }

실제로 사용되는 것은 ASSERT_TRY, ASSERT_CATCH, USE_ASSERT_TRY의 3개의 매크로이다.

USE_ASSERT_TRY:
assertion catch 기능을 사용하겠다는 선언이다. 만약 이것이 선언되지 않는다면 관련 매크로는 모두 무시된다. 이것을 선언하는 시점 이후로만 관련 매크로가 활성화된다.

ASSERT_TRY:
일반적으로 사용되는 try - catch 구문의 try와 동일한 용법이다. 이 내부에서 assertion이 일어났을 때 catch 구문으로 점프한다.

ASSERT_CATCH:
일반적인 try - catch 구문에서 catch에 해당한다. 단지 error handling을 위한 class를 받는 부분은 빠져 있는데 그것이 필요하다면 추가하면 된다. (하지만 다중 파라미터에 대한 catch가 될런지는 의문)

사실 내용은 전혀 C++이 아니고 C에서 사용된 error handling 기법을 사용하였다. (VC++의 디버그 모드에서 테스트 하면, assert에 대한 것을 중간에 IDE가 먼저 감지를 하는데 그땐 '무시'를 눌러 주면 된다.)