본문 바로가기
C.C++/코드

assertion

by 겜게준 2017. 5. 18.

assertion은 간단하게 말해서 프로그램 실행시간에 조건을 강제한다고 보면 된다. 다른말로 하자면 그 조건에 무조건 만족해야만 하도록 할 때에 그 조건을 검사하기 위해 하는것이라고 보면 된다. 또 다른말로 하자면 에러검출, 데이터체킹이라고 보면 된다.


cassert에 적혀있는 assert는 다음과 같다.

#ifdef NDEBUG
 
    #define assert(expression) ((void)0)
 
#else
 
    _ACRTIMP void __cdecl _wassert(
        _In_z_ wchar_t const* _Message,
        _In_z_ wchar_t const* _File,
        _In_   unsigned       _Line
        );
 
    #define assert(expression) (void)(                                                       \
            (!!(expression)) ||                                                              \
            (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \
        )
 
#endif


컨디션을 체크하여 컨디션 식이 false값일 때 _wassert에 컨티션 식과 파일 경로를 문자열 리터럴로 넘겨주고 메크로 함수가 작성되어있는 라인 수를 unsigned로 넘겨준다. 그 후 포맷에 맞게 값을 출력한다.


참고로 참값은 0이 아닌 값이었기 때문에 추가로 메시지를 출력하기 위해서

assert(0 != 0 && "Dfadsfad");


와 같이 작성할 수 있다. 왜냐하면 "Dfadsfad" 값은 0이 아닌 값이기 때문에 true로 판별될 것이기 때문에 assert에서 걸릴 시에, 위의 식대로 출력이 될 것이기 때문이다.


하지만 나는 이것보다 조금 더 많은 데이터와 원래와는 다른 출력 포맷, 추가 메시지를 더욱 명확히 주고 싶었다.




헤더

/* jwqe764241 작성 */ #ifndef ERROR_H #define ERROR_H #include <Windows.h> #include "defs.h" //디버그 모드일때 #ifndef NDEBUG #define ERROR_TEST_ENABLE #endif __JWQE764241_START namespace error { typedef LONG ERROR__; void __cdecl ErrorHandler( _In_ char const * const fileName, _In_ char const * const funcName, _In_ const unsigned lineNumber, _In_ char const * const condition, _In_ char const * const message ); } END_JWQE764241__ #define CUSTOM_ASSERT(condition, message) \ if (!(condition)) { \ jwqe764241::error::ErrorHandler(__FILE__, __FUNCTION__, __LINE__, #condition, message); \ } \ #define TEST____(message) \ { \ std::cout << "TEST : "; \ std::cout << message << std::endl; \ } \ //켜졌을 때 #ifdef ERROR_TEST_ENABLE #define jwqe764241_ASSERT(condition, message) CUSTOM_ASSERT(condition, message) #define jwqe764241_TEST(message) TEST____(message) #else //디버그 모드가 아니면 아무 동작 하지 않음 #define jwqe764241_ASSERT(condition, message) #define jwqe764241_TEST(message) #endif #endif


cpp

/* jwqe764241 작성 */ #include "../h/error.h" #include <iostream> #include <stdlib.h> //상관쓰지 말기 ㅎ void __cdecl jwqe764241::error::ErrorHandler( _In_ char const * const fileName, _In_ char const * const funcName, _In_ const unsigned lineNumber, _In_ char const * const condition, _In_ char const * const message ) { std::cerr << "-------------------------------------" << std::endl; std::cerr << "Assertion Get False" << std::endl; std::cerr << "      File : "<< fileName << " : " << lineNumber << " Line at " << funcName << std::endl; std::cerr << "      Condition Expression → " << condition << std::endl; std::cerr << "      message : " << message << std::endl; std::cerr << "-------------------------------------" << std::endl; //강제종료 -> abort() 호출 abort(); }



# 구문을 통해서 컨디션 체크할 수식을 문자열 리터럴로 넘겨주었고, 미리 정의된 상수를 이용하여 로그를 찍을 수 있도록 하였다.


NDEBUG는 DEBUG 모드가 아닐 때 정의된다. 그렇기 때문에 DEBUG 모드가 아니면 jwqe764241_* 정의들이 매크로 함수로 치환이 되지 않기 때문에 아무 동작도 하지 않는다.


보통 assert는 해당 구문이 무조건 참값이어야 하고, 거짓값일 때에는 심각한 에러를 나타내므로 에러처리로 예외로 넘기기 보다는 프로그램을 강제종료 시켜서 정확히 짚어낼 수 있게 하였다.


뭐 일단 저렇게 사용하곤 있지만, 방식을 바꿀 수 있기 때문에 여기까지 하겠다.

댓글