블로그 이미지
자신의 단점을 메꾸는 것을 단(鍛)이라 하고 자신의 강점을 갈고 닦는 것을 련(鍊)이라 하여, 두가지를 합친 것을 단련이라고 부른다. 붕대마음

카테고리

전체목록 (667)
참고사이트 (8)
Goal (4)
Travel (10)
My Life (105)
Game (35)
Game Review (7)
Game Plan (0)
Books (5)
English (1)
Optimizing (12)
Study (218)
유용한 것들_etc (44)
유용한 것들_func (20)
Unity (48)
Unreal (87)
작업장 (54)
RenderMonkey (6)
정리요망 (1)
따라잡기 시리즈 (0)
링크용 (0)
Total345,595
Today85
Yesterday123

compile time assertion

Study/C++ / 2010. 6. 10. 22:20

중요한 안건은 두가지.
runtime assert를 compile time assert로 대체.
이를 대체하면서 적절한 에러메세지 출력.

안전한 형변환을 위해 아래와 같이 만들었다고 생각해보자.
#include <assert.h>

// 안전한 형변환을 위해 선언.
template <class To, class From>
To safe_reinterpret_cast(From from)
{
 assert(sizeof(from) <= sizeof(To));
 return reinterpret_cast<To>(from);
}

int _tmain(int argc, _TCHAR* argv[])
{
 int i   = 4;
 char* p = safe_reinterpret_cast<char*>(i);
 return 0;
}

즉, To에 쓰인 자료형이 From에 쓰인 자료형의 모든 비트데이터를 수용할 수 있는 크기인지가 관건이다.
그렇지 않다면 assert(런타임 어설트)가 발생한다.

만일, 이러한 에러를 컴파일 타임에 잡아낼 수 있을까?
관심있게 봐야 할 부분은 assert() 함수 이다.
이 구문에서 인자로 사용되고 있는 비교식은 컴파일러 입장에서 볼 때 상수로 분류된다.
즉, 컴파일러에게 0이 아닐 경우에는 적법하고, 0일 경우에는 문제가 되는 구문을 언어적 구조로 표현하여
넘겨주면 되지 않을까?..

0일 경우에 문제가 되는 구문중 하나가 길이가 0인 배열이다.
c와 c++에서는 길이가 0인 배열을 허용하지 않는다는 것에 주목하자.
아래와 같이 매크로를 살짝 만들어 줄 수 있다.
#define  STATIC_CHECK(expr) {char unnamed[(expr)?1:0];}

이제 컴파일 타임 어설트도 만들었으니 런타임 어설트를 대신하여 사용해 보자.

template <class To, class From>
To safe_reinterpret_cast(From from)
{
 STATIC_CHECK(sizeof(from) <= sizeof(To));
 return reinterpret_cast<To>(from);
}

int _tmain(int argc, _TCHAR* argv[])
{
 int i   = 4;
 void* point = &i;
 char p = safe_reinterpret_cast<char, void*>(point);
 return 0;
}

이를 컴파일 하면 "error C2466: 상수 크기 0의 배열을 할당할 수 없습니다."와 같은 문구가 뜨면서 컴파일시 에러가 뜬다.

이제 에러메세지에 특별한 의미를 부여해야 한다.
컴파일러는 에러메세지에서 템플릿의 이름을 언급해 줄 수 있다.
template<bool> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
#define  STATIC_CHECK2(expr) (CompileTimeError<(expr) != 0>())

위와같이 bool상수를 인자로 하고, bool값이 true인 경우에 대해서만 정의하므로
false에 대한 템플릿의 특화는 정의돼어 있지 않다는 에러메세지를 받을 수 있다.
이 에러메세지는 프로그래머가 의도한 에러메세지임을 알아야 한다.

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }


// 안전한 형변환을 위해 선언.
template <class To, class From>
To safe_reinterpret_cast(From from)
{
 STATIC_CHECK(sizeof(from) <= sizeof(To), Destination_Type_Too_Narrow)
 return reinterpret_cast<To>(from);
}

define static_check가 false를 얻으면 컴파일 타임에서 에러가 나고 에러메세지는
정의한 메크로에 의해 아래와 같은 형식으로 출력이 된다.

'ERROR_Destination_Type_Too_Narrow'은(는) 정의되지 않은 struct 'CompileTimeError<__formal>'을(를) 사용합니다.
위의 메세지를 통해 디버깅을 좀 더 빨리 편하게 할 수 있다.

'Study > C++' 카테고리의 다른 글

warning C4251  (0) 2010.06.26
참조카운팅 + 스마트포인터 템플릿  (0) 2010.06.16
compile time assertion  (0) 2010.06.10
FileChecker  (0) 2010.06.09
STL의 std::string::find_last_of 사용 시 주의 사항  (0) 2010.06.04
__int8, __int16, __int32, __int64  (0) 2010.05.30
Posted by 붕대마음

댓글을 달아 주세요

최근에 달린 댓글

최근에 받은 트랙백

글 보관함