블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2794)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (11)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

매크로는 C와 C++에서 제공되는 꽁수같은 기능이라고 할 수 있습니다.

꽁수같다라고 한 이유가  매크로는 사용자의 편의와 동시에 많은 위험성을 초래하기 때문이죠.

그래서, 대부분의 서적에서는 매크로의 사용을 자제하고 인라인(inline)과 상수형(const)을 더 지향하기도 합니다.

 

하지만, 이는 단순히 매크로의 위험성 때문이며 그 위험성의 간단한 예를 들자면,

 

#define POW( A ) A * A        // 정의했을 경우

...

POW( 10 + 10 )                // 사용자의 의도는 20 * 20 입니다.     하지만 결과는,

10 + 10 * 10 + 10             //10 + 100 + 10 = 120 이죠.

 

또한, 상수형 같은 경우는 디버깅이 불가능하다는 점도 있죠. 최근에 좋은 개발 툴은 매크로 변수를 추적도 가능하다고 합니다만... 비주얼 스튜디오 2008에서도 아직 안되더군요. :|

 

어쨌든, 그런 위험성을 제거할 수 있고 개발자 편의로 매크로를 마음껏 사용할 수 있다면, 구지 매크로를 사용을 자제할 필요가 없다고 봅니다.

 

결론은, 매크로의 사용여부는 개발자 자신에게 넘기도록 하겠고, 오늘은 매크로의 비법들에 대해서 한번 살펴보도록 하겠습니다.

매크로 사용여부는 다 알고 계신다고 가정하고, 사용 설명은 따로 하지 않겠습니다. 간단한 예를 보면 쉽게 이해가 될 겁니다.

 

#1) 열거형을 문자열로

 #define CaseEnum( A )      case( A ) : LogMsgToFile( #A )

 

switch( msg ) {

  CaseEnum( MSG_One );

    ...

    break;

  CaseEnum( Msg_Two );

    ...

    break;

  default:

    ...

    break;

}

 

/*************컴파일 전처리가 끝나면, 위의 소스는 다음과 같이 대체 됩니다.***********************/

 

switch( msg ) {

  case( MSG_One ): LogMsgToFile( "MSG_One" );

    ...

    break;

case( MSG_Two ): LogMsgToFile( "MSG_Two" );

    ...

    break;

  default:

    ...

    break;

}

 

 #2) 두 인자를 하나의 값으로 합치기

#define CAT( A, B )    A ## B

 

value = CAT( 1, 2 );

 

/*************컴파일 전처리가 끝나면, 위의 소스는 다음과 같이 대체 됩니다.***********************/

 

value = 12;

 

 #3) 표준 assert에 의미있는 메세지 추가하기

#define ASSERT_MSG( A, B )  assert( a && b )  

 

ASSERT_MSG( time > 0, "time must be bigger than zero" );

 

/*************컴파일 전처리가 끝나면, 위의 소스는 다음과 같이 대체 됩니다.***********************/

 

assert( time > 0 && "time must be bigger than zero" ); 

 

//사용에 있어서 큰 차이는 없지만 매크로가 더 사용자 직관적이지 않나요?

 

 #4) 컴파일 시점의 assert

//애초에 제한 조건에 벗어나면 컴파일 오류를 발생 시킵니다.

#define CASSERT( A ) typedef char __C_ASSERT__[ (A) ? 1: -1 ]

 

CASSERT( sizeof( MyEnum ) == sizeof( unsigned int ) );

 

/*************컴파일 전처리가 끝나면, 위의 소스는 다음과 같이 대체 됩니다.***********************/

 

//만약 MyEnum의 크기가 16이라고 가정했을 때,

typedef char __C_ASSERT__[ ( 16 == 4 ) ? 1: -1 ]

 

16 == 4는 거짓이며 따라서 __C_ASSERT[ -1 ] 이라는 형을 정의하려고 합니다.

하지만, -1의 크기의 배열 정의는 컴파일러 입장에서 불가능하기 때문에 잡아낼 수 있죠. 

 

#5) 배열의 원소를 구하기

//자바 같은 경우는 배열의 원소 갯수를 알 수 있지만 C/C++ 에서는 기본적으로 제공되진 않습니다. 

#define NUM_ELEMENT( A ) ( sizeof( A ) / sizeof( ( A[ 0 ] ) )

 

int a[ 10 ]

int nElement = NUM_ELEMENT( a );

 

/*************컴파일 전처리가 끝나면, 위의 소스는 다음과 같이 대체 됩니다.***********************/

 

int a[ 10 ]

int nElement = 40 / 4;

 

#6) __LINE__을 문자열로

// 기본적으로 정의되어 있는 유용한 매크로들 입니다.

__LINE__ // 컴파일 시점의 행 번호를 의미하는 정수

__FILE__ // 컴파일 되는 파일 이름을 담은 문자열

__DATE__ // 컴파일 될 때의 날짜를 담은 문자열

__TIME__ // 컴파일 될 때의 시간을 담은 문자열

 

//이들을 디버깅 시 유용히 활용할 수 있습니다.

#define TO_MSG( X ) #X

 

#define __FILELINE__ __FILE__" ( " TO_MSG(__LINE__) " ) "           //VC++에서는 안될 수도 있음

 

/*************컴파일 시 다음과 같이 출력됩니다.***********************/

c:\project\main.cpp ( 105 )

 

 

 

-참고 : Game Programming Gems 3 ( 정보문화사 )-


 
[출처] 매크로 마법 (Macro)|작성자 Hermet

반응형
Posted by blueasa
, |