ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C/C++]#define 매크로 팁
    개발/C/C++ 2007.06.29 07:56


    C/C++ 에서 #define 을 사용을 가급적 자제하도록 권고되고 있지만, 잘 사용할 경우 많은 코딩상의 이득을 볼 수 있습니다.  

    #define을 활용하는 예를 몇 가지 설명하려고 합니다.

     

    우선 팁을 설명하기 전에 간단하게 ‘##’ “#’ 에 대해 살펴보고 가겠습니다. (샘플소스는 MSDN 에서 가져왔습니다)

     

    1.     ‘##’ - Token-Pasting Operator (##): 분리되어 있는 2개의 토큰을 하나로 뭉쳐주는 역할을 합니다.

    #define paster( n ) printf( "token" #n " = %d", token##n )


    라고 할 때 아래와 같은 코딩은

    int token9 = 9;

    paster( 9 ); // token##n -> token 과실제인수9 를합쳐token9 가됨


    다음과 같이 풀이되어 결국 ‘token9 = 9’ 가 화면에 표시되게 됩니다.

    printf( "token" "9" " = %d", token9 );

    printf( "token9 = %d", token9 );


    이와 같이 ## 은 왼쪽 Operand 와 오른쪽 Operand를 접착제처럼 붙여 주는 역할을 합니다.

     

    2.     ‘#’ - Stringizing Operator (#): 매크로 인자를 문자열로 만드는 역할을 합니다.

    #define stringer( x ) printf( #x "\n" )


    과 같이 정의 할 경우 아래와 같은 문장은

    stringer( In quotes in the printf function call\n );


    다음과 같이 풀어쓰게 됩니다.

    printf( "In quotes in the printf function call\n" "\n" );

     

    이제 #define 매크로를 이용한 활용예를 들어 보겠습니다.

    1.    배열의 크기 구하기


    #define 을 이용하는 가장 간단하고 자주 쓰이는 팁이 아닐까 생각됩니다.

    #define arrayCnt( x ) sizeof(x) / sizeof(x[0])


     이를 이용한 간단 샘플입니다.

    struct LIST_COL_DEF

    {

               int nChar;

               char szText[20];

    } ListCol[] =

    {

               {20, "폴더"},

               {20, "파일명"}

    };

    for (int i = 0; i < arrayCnt(ListCol); i++)

    {

               // To Do Something...

    }

     

    물론

    i < arrayCnt(ListCol)

    를 사용하지 않고

    i < sizeof(ListCol) / sizeof(ListCol[0])

    을 사용해도 되지만 이와 같은 작업을 여러 번 반복할 경우(array 를 사용하는 경우는 정말 흔하디 흔하죠) 단조로운 코딩이 반복될 수 있어 #define 을 이용한 매크로를 애용하고 있습니다.

     

    2.    Get/Set 함수 간단하게 만들기

    OOP(Object Oriented Programming)로 프로그램 할 경우 멤버 변수의 Get 함수와 Set 함수를 만들어야 할 경우가 많습니다. 변수를 외부로 드러내지 않고 변수에 대한 접근 Method 만 제공함으로써 추후 변경에 대한 유지보수를 최소화하기 위해 많이 사용하게 되는데요(OOP 의 특징 중에 하나인 Encapsulation). 간단한 Get/Set 함수라 하더라도 하드코딩일 경우 손이 많이 가게 됩니다. 이럴 경우 #define 매크로를 사용하면 단순반복적인 Get/Set 함수를 한 줄만으로 코딩하여 작성할 수 있습니다.


    예를 들어 다음과 같은 매크로를 정의한 경우

    // SIMPLE_FUNC_IMPL -> Get/Set 함수를자동으로만들어줍니다.

    // 1. ret -> return type

    // 2. fname -> Get/Set 다음에올함수명

    // 3. var -> Get/Set 에대상이되는변수명

    #define SIMPLE_FUNC_IMPL(ret, fname, var) \

               ret Get##fname() \

               { \

                         return var; \

               } \

               void Set##fname(ret tmp) \

               { \

                         var = tmp; \

               }

     

    bool m_bTest Get 하고 Set 하는 간단한 함수는 아래 한 줄로 만들 수 있게 됩니다.

    SIMPLE_FUNC_IMPL(bool, Test, m_bTest);


    위 한 줄의 매크로는 자동으로 전 처리기에 의해 컴파일 시 다음과 같은 함수로 확장됩니다.

    bool GetTest()

    {

               return m_bTest;

    }

    void SetTest(bool tmp)

    {

               m_bTest = tmp;

    }


    간단하지 않은가요 ^^.

    외부로 공개해야 하는 속성이 많으면 많을수록 코딩부담을 줄이고, 미스타이핑으로 인한 오류를 사전에 막아 줄 수 있어 매크로는 더욱 위력을 발휘하게 됩니다.

    사실 마이크로소프트의 ATL 3.0 라이브로리 소스 헤더를 분석해 보면 이와 같은 매크로를 훨씬 복잡하게 사용하고 있다는 걸 알 수 있습니다.

    아래 샘플은 ATL 3.0 라이브러리 ATLCTL.H 소스에 있는 코드입니다. (소스가 길어 접습니다

     

    소스코드 열기

     

     끝으로, 이와 같은 #define 매크로의 단점도 잠시 언급하면

    -       디버깅이 힘듭니다. 디버깅 시 매크로의 경우 확장된 소스가 보여지지 않아 변수의 변경사항을 추적해 들어 가기가 힘듭니다. 매크로가 복잡할 경우 애로가 있을 수 있어 복잡한 함수의 경우는 위와 같은 방식을 취하지 않는 편이 좋습니다.

    -       #define MAX_CUSTOMER 10 보다는
    const int MAX_CUSTOMER = 10
    으로 코딩 하는 것이 변수가 잘못 typecasting 되는 걸 막을 수 있는 좋은 코딩 습관입니다. 사실 이 부분 때문에 #define 매크로사용을 자제해야 한다고 권장한다고 봐야겠죠.

     

    이상으로 #define 매크로에 대해 아주 간단한 팁을 알아봤습니다. 사실 초보자가 아닌 경우 대부분 아실 만한 내용이라 적기가 부끄러운 내용이긴 한데 기록해 둘 경우 나중에 기억이 가물가물해 졌을 때나, 프로그램을 시작하는 다른 분들에게 도움이 될까 하고 적어봤습니다. 오늘도 열코!!

     


    댓글 15

    • 프로필사진

      신가하네요. 매크로를 이용해서 set, get을 구현하는 거죠?
      좋은 정보 많이 배우고 갑니다.

      2010.05.06 14:50 신고
      • 프로필사진

        네 구찮은 get/set 함수 반복에는 매트로가 딱인데.. 저런 스타일 싫어하시는 분도 있으니 조심하세요 ㅎㅎ. 저는 좋아합니다 날코딩이 줄면 오류도 주니까요

        2010.05.06 20:50 신고
    • 프로필사진

      사실 예전에 제가 봤던 코드중에 #define 으로 거의 모든 코드가 작업된 작업물이 있었습니다.
      그때 ##의 기능이 아주 엄청난 기능이라는걸 알았습니다.ㅋ

      여기서 보니 감회가 완전 새롭네요!

      2012.03.29 10:52
      • 프로필사진

        요즘 자바 코딩하는 중인데, 반복적인 일들은 매크로가 그립습니다. ㅎ

        2012.04.08 10:07 신고
    • 프로필사진

      이야.. 정말 감사합니다!! :)
      c++ 하면서 property 다 적는게 너무 귀찮았는데, 최고네요!!
      정말 많은걸 배워갑니다!!

      2012.05.29 17:26 신고
      • 프로필사진

        요즘은 c++ 개발자가 드문데 반갑네요
        저는 거의 개발을 안하고 있긴 하지만 ^^

        2012.05.29 22:03 신고
    • 프로필사진

      잘배우고 갑니다~

      2013.12.17 22:28
    • 프로필사진

      네이버 카페에 올리고싶은데요. 학교에서 만든 동아리개념의 카페에 프로그래밍 팁 글로 올리고싶은데.. 출처 적고 퍼가도되나요?

      2014.01.01 19:51
      • 프로필사진

        네. 출처 명기 하신다면 이 글은 공유 가능합니다. 즐거운 공부 되세요

        2014.01.01 19:54 신고
    • 프로필사진

      감사합니다 좋은하루되세요..^^

      2014.01.01 22:29
    • 프로필사진

      혹시 앞부분 글자를 취환할 수 있는 방법은 없나요?

      예를들어
      다음 두 프로그램이 있으면 프로그램#1은 가능한데,
      프로그램#2는 컴파일이 안되네요.
      프로그램#2 처럼 하려고 하거든요. 원래 안되는 건지.... 도움 좀 부탁드립니다

      <프로그램#1)

      #include <stdio.h>
      #define GET_VAL_1(str, val) val=test##str##test
      int main()
      {
      int ret;
      int testaaatest=100;

      GET_VAL_1(aaa, ret);
      printf("ret = %d\n", ret);

      return 0;
      }

      <프로그램#2>

      #include <stdio.h>
      #define GET_VAL_2(str, val) val=##str##test
      int main()
      {
      int ret;
      int aaatest=100;

      GET_VAL_2(aaa, ret);
      printf("ret = %d\n", ret);

      return 0;
      }

      2014.06.25 14:03
      • 프로필사진

        ## 는 붙어 있는 두개의 문자를 합쳐주는 거라 앞에서 붙이는 용도는 안 맞습니다
        어느 용도인지 모르지만 ## 이나 # 만으로는 힘들어 보이네요

        2014.06.26 21:17 신고
    • 프로필사진

      와 define으로 이런게 가능했군요! 정말 놀랍습니다. 항상 C++ 프로그래밍을 할 때 get set 함수를 만들기 귀찮았는데 이런게 있었다니 정말 다행입니다. 저와 같은 사람에겐 이런 포스팅이 너무나 고맙습니다! 감사합니다.

      2015.10.07 15:30
      • 프로필사진

        오래 전에 저도 한 참 공부 할 때 적은 글인데 이렇게 오랜 시간 지나고도 피드백을 받을 수 있어 좋네요 . 감사합니다 저도 인터넷에서 많은 공부를 배웠고 지금도 그래요 . 행복한 개발 생활 되시길 빌게요 :)

        2015.10.07 15:33 신고
Designed by black7375.