런타임
ASSERT, VERIFY, 그리고 TRACE
Using ASSERT(), VERIFY(), and TRACE() in non-MFC Applications에 따르면 ASSERT, VERIFY, TRACE 는 다음과 같은 차이를 보인다.
- ASSERT(expr)는 TRUE, FALSE(0)로 판별 가능한 표현식을 매개변수로 받는다. 표현식이 FALSE로 판명되면 응용프로그램을 멈추고 사용자에게 문제를 알린다. 이때 사용자는 디버거를 붙일지 여부를 선택한다.
- ASSERT()는 디버그 빌드 때만 작동한다. 릴리즈 빌드시엔 문제를 통지 안 할뿐더러 표현식 자체도 평가하지 않는다.
- VERIFY(expr)는 ASSERT와 동일한 역할을 한다. 차이점이라면 릴리즈 빌드 때도 작동한다는 것이다.
- TRACE(expr)는 printf()와 비슷한 역할을 한다. 단지 표준 출력 장치가 아닌 디버그 윈도우에 메시지를 출력할 뿐이다. 응용프로그램에 Visual Studio 등의 디버거를 붙이지 않았더라도 메시지를 볼 수 있다. Sysinternals의 DebugView 같은 도구는 디버거가 없는 프로덕션 서버에서 응용프로그램의 문제를 확인하게 해준다.
BOOST_ASSERT
배울 점
문제점
namespace boost { void assertion_failed(char const * expr, char const * function, char const * file, long line); // user defined } #define BOOST_ASSERT(expr) ((expr)? ((void)0): ::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))
BOOST 라이브러리는 교과서나 다름 없을 만큼 깔끔한 코드를 보여준다. 그러나 이토록 아름다운 코드에도 의외로 큰 문제가 있으니, 핵심 코드 자체가 문제다. 위의 코드에 어떤 문제가 있는지 알겠는가? 의외로 간단하다. 함수 이름(BOOST_CURRENT_FUNCTION)과 파일 이름(__FILE__)을 한 바이트짜리 문자 코드(char)로 전달하고 받는다는 문제가 있다.
앞서 알아봤듯 윈도우는 ANSI가 아닌 유니코드를 기반으로 다시 작성됐고, 유니코드를 썼을 때 성능이 좋다. 또한 우리가 한글을 쓴다는 점, 보다 넓은 국제 시장을 목표로 삼는 요즘의 경향을 고려하면 유니코드는 필수적이다. 그밖에도 유니코드를 쓸 이유는 많다. 예를 들면, 다음의 소스코드처럼 함수 이름을 한글로 지은 경우가 있겠다.
struct UnicodeClass { void 가나다() { } };
이런 이유 때문에 Boost 라이브러리를 다음과 같이 바꾸어야 한다.
namespace boost { void assertion_failed(TCHAR const * expr, TCHAR const * function, TCHAR const * file, long line); // user defined } #define BOOST_ASSERT(expr) ((expr)? ((void)0): ::boost::assertion_failed(TEXT(#expr), TEXT(BOOST_CURRENT_FUNCTION), TEXT(__FILE__), __LINE__))
물론 외부 라이브러리의 소스 코드를 직접 고치면 불리한 점도 있다. 나중에 최신 버전의 Boost 라이브러리로 업데이트한다면 방금 전에 한 일을 반복해야 한다. 다행히 BOOST_ASSERT는 비교적 코드가 간단하다. 그러므로 코드를 복사해 필요한 부분만 고치면 된다. 이런 방식은 Boost 라이브러리를 업데이트해도 응용프로그램엔 영향을 미치치 않는다는 장점이 있다.
컴파일 타임에 평가하기
글 써야 함
고전적인 BOOST 의 구현 방식
글 써야 함
C++11
으하하 array, template 다 꺼져버리라 그러고 C++11 으로 행복한 세상~