반응형

Assert 매크로 커스텀  VC++ Tip 

2012/03/22 19:45

복사http://neosafe.blog.me/130134400429


본 내용은 VisualStudio 2010 기준으로 작성 되었습니다.

 

어느 C++책을 보더라도 NULL 검사는 꼭 하라고 나옵니다. 

 

개인적으로는 NULL 검사나 ASSERT를 자주 쓰는 편입니다.

 

그런데 일반적인 ASSERT함수는 디버깅시에 함수안쪽으로 한단계 더 들어가야하기 때문에 늘 귀찮습니다.

 

그래서 늘 새 프로젝트를 할때마다 NULL체크 함수와 ASSERT체크 함수를 꼭 만들어서 쓰는데 만들때마다 자꾸 조금씩 까먹어서 이 참에 블로깅을 할까 합니다.

 

#define _AssertF( _val, _msg)  { if( _val == false) { MessageBox(NULL, _msg, "Assert Message", MB_OK); __asm { int 3 }; } }

#define _AssertT( _val, _msg) { if( _val == true) { MessageBox(NULL, _msg, "Assert Message", MB_OK); __asm { int 3 }; } }

#define _Assert( _val, _msg) { { MessageBox(NULL, _msg, "Assert Message", MB_OK); __asm { int 3 }; } }

 

첫번째 _AssertF는 _val에 해당하는 토큰(taken)이 false일때 _msg에 해당하는 문자열 토큰이 브레이킹(메세지와 함께 일시적 멈춤)과 함께 출력 됩니다.

두번째 _AssertT는 _val에 해당하는 토큰이 true일때 _msg에 해당하는 문자열 토큰이 브레이킹과 함께 출력 됩니다.

두개를 구분해 놓은 이유는 기본 ASSERT는 false 중심인데 개인적으로는 이를 맞추기가 좀 헷갈려서 입니다.

세번째 _Assert는 무조건 _msg에 해당하는 문자열 토큰이 브레이킹과 함께 출력 됩니다.

 

" __asm { int 3 }"는 어셈블리코드로써 인터렙트를 발생시키라는 뜻입니다.

 

결국은 아래의 코드처럼 사용하면 됩니다.

 

//m_bHave가 false일 때 문제가 있음을 감지

_AssertF( m_bHave, "m_bHave가 false입니다." );

 

//m_bHave가 false일 때 문제가 있음을 감지

_AssertF( m_pValue1 == m_pValue2, "같은 값이 들어왔습니다." );

 

//바로 경고를 띄웁니다.

if( m_pValue == NULL )

{

 _Assert("m_pValue가 NULL입니다.");

}

 

같이 말한 것으로 NULL체크 함수도 있습니다.

 

#define _NullCheckRet( _val, _ret, _msg ) { if( _val == 0) { MessageBox(NULL, _msg, "NullCheck Message",MB_OK); __asm { int 3 }; return _ret; } }

#define _NullCheck( _val,  _msg ) { if( _val == 0) { MessageBox(NULL, _msg, "NullCheck Message",MB_OK); __asm { int 3 }; } }

 

첫번째 NULL체크 매크로는 _val에 해당하는 값이 0, 즉 NULL이 되었을때 _msg의 문자열에 해당하는 토큰을 출력하며 발동합니다.

리턴값(_ret)도 삽입할 수 있습니다.

두번째 NULL체크 매크로는 _val에 해당하는 값이 0이면 무조건 _msg의 문자열에 해당하는 토큰을 출력하며 발동합니다.

 

_Assert매크로와 _NullCheck매크로와의 차이점은 _Assert는 경고이고 범용적이며 계속 진행이 가능한 코드임에 반해 _NullCheck는 경고이며 포인트를 사용한 변수에게만 한정적으로 쓰고 조건에 해당할때는 그 하단의 코드들은 실행하지 않겠다는 뜻으로 사용합니다.

 

_NullCheck( m_pSprite, "스프라이트정보가 없습니다." );

//m_pSprite이 NULL이라면 하단 코드는 실행하지 않고 바로 return 합니다.

m_nValue = m_pSprite->GetValue();

m_pSprite->SetIndex(m_nIndex);

 

bool SetValue( Sprite* _pSprite)

{

_NullCheckRet( _pSprite, false, "SetValue을 하는 도중 pSprite가 NULL입니다."

//_pSprite이 NULL이라면 하단 코드는 실행하지 않고 바로 return false합니다.

m_nValue = _pSprite->GetValue();

_pSprite->SetIndex(m_nIndex);

}

 

중요한건 매크로 제작시에 최대한 VC의 버젼에 따른 변경사항이 반영되지 않게 했습니다.

또한 #define 대신에 inline 함수를 사용해도 되지만 그렇게 되면 디버깅시 한스택 더 타고들어가는 불편함을 또 겪어야하기 때문에 의미가 없습니다.

 

더 추가하자면 __FUNCTION__이나 __LINE__ 같은 것들을 추가할 수 있지만 개인적으로는 복잡하게 정보가 출력되는 것을 그다지 좋아하진 않습니다만 취향에 따라 넣을 수도 있겠습니다.

 

그리고 "__asm { int 3 }" 대신에 "DebugBreak()"로 대신 할 수 있습니다.

차이점이라면 어셈블리코드로 짠 브레이킹방법은 해당 스택(함수안)에 중단점을 걸었을 경우 브레이킹이 되지 않는다는 것(VC2010기준)이고 함수를 이용한 방법은 어느때고 브레이킹이 된다는 겁니다.

 

좀 귀찮긴 하지만(사실 많이 귀찮..) Assert와 Null 검사는 많이하면 많이 할 수록 좋습니다.

그 결과에 대한 보담은 프로젝트 막마지에 버그 갯수로 말해 줄겁니다.

반응형

+ Recent posts