출처 :

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=4472&ref=1503

 


1. 동기 
- window프로그래밍이나 mfc 프로그래밍을 할 때, 에러나 내부적인 상태를 표현하기 위해서 
  기존의 경우 MessageBox()를 이용했으나 어떤 상태등을 표시하기엔 상당히 귀찮았죠. 
  그래서 마치 자바 처럼 따로 콘솔창을 띄워서 알리고 싶은 사항을 그곳에 표시함으로써 
  프로그램의 디버깅용 창을 따로 띄워 놓는 것입니다. 
   (특히 화면 갱신에 대한 내용등을 처리할 때는 이렇게 하면 상당히 편리 하겠죠)

2. 사용법 
- 1. 클래스를 프로젝트에 포함 
  2. stdafx.h 에 #include "debugconsole.h" 
  3. CONSOLE("화면 갱신했습니다. 지금 값은 %d 입니다.", i);       // 이런 식으로 사용. 

3. 사용된 내용. (단순히 사용이 아니라 좀 더 자세히 알고 싶은 분들만 읽어보시길.. ^_^)
기본적으로는 콘솔을 띄우고, 상태를 표시하는 것이지만 몇가지 내용이 들어갔으니 잘 봐주시길... 

* 콘솔창 띄우기
    AllocConsole();             // 콘솔창 만든다.
    m_hOut = GetStdHandle(STD_OUTPUT_HANDLE);     // 콘솔창의 핸들 가져옴.
    WriteConsole(m_hOut, strBuffer, strlen(strBuffer), &dwWrite, NULL); // 콘솔창에 쓸때
    FreeConsole();              // 콘솔창을 없앰.
이건 몇가지 간단한 api만 알고 계시면 됩니다. ^_^

* singleton (단일체) 
이유 : 프로그래머가 debugconsole 클래스를 위한 객체를 따로 생성하지 않아도 될뿐만 아니라
            전체 프로그램에서 디버깅 콘솔창은 딱 1개만 띄운다는 것을 보장해줌.
코드 : 
        static CDebugConsole& getConsole()     // 해당 클래스 안에 있음. 
        { 
                static CDebugConsole gt; 
                return gt; 
        } 
설명 : 그러니까 매번 젤 위에 CDebugConsole g_console; 이런식으로 전역 변수로 선언하지 않고, 
            헤더만 포함한 후에 쓰기만 하면 되도록 할 수 있도록 하기 위한 것이구요. 
             (프로그램 실행시 자동으로 객체가 생성됩니다.)
            static의 특성을 이용한 것입니다. 
            특히, debugging console 창이 2개가 뜰 순 없기 때문에 단일체의 개념이 맞다고 할 수 있죠. 
            프로그램 안에서 딱 하나만 존재해야 하고, 언제든지 써야 한다면, 단일체를 사용하시구요. 
            제가 쓴 단일체는 제일 기본적인 단일체고 좀 더 다양한 단일체를 쓰고 싶으신 분은 
            More Effective C++ 의 item 26을 참조하시기 바랍니다 ^_^ 
            Game Gems 1에도 있군요. 
             
*  " ... " 키워드의 사용 
이유 : 만약에 그냥 print(char* szMsg)라고 한다면, 표현이 상당히 제한 될 수 있지만, 
            " ... " 을 통해서 print( " 하하 나는 %d 번째 실행됐다. " , i ); 나 %s 등등으로 자유롭게 표시 가능. 
코드 : 
void CDebugConsole::print(TCHAR *tszMsg, ...) 

    TCHAR strBuffer[512]; 

    va_list args; 
    va_start(args, tszMsg); 
    _vsntprintf( strBuffer, 512, tszMsg, args ); 
    va_end(args); 

        DWORD dwWrite; 
        WriteConsole(m_hOut, strBuffer, _tcslen(strBuffer), &dwWrite, NULL); 

설명 : 여기서 va_list나 va_start 등등 평소 자주(?) 못보던 함수들이 보이시죠? 
           (물론 " ... "이 생소하신 분들도 많으시겠지만 ㅡ.ㅡ...) 
            자세하게 할 껀 없고, 그냥 이런 식으로 인자값의 제약을 뛰어 넘었다는 것을 봐주세요 ^_^

* DEFINE의 사용.
자...여기까지 공부하신 분이라면, 이제 프로그램에서 객체를 생성하지 않고도 단지 헤더파일만 포함한 담에
CDebugConsole::getConsole().print( "지금은 %d번째 화면 갱신을 했습니다. " , i );
라고만 쓰면 디버깅 콘솔에 표현이 되지만......타자치기엔 너무 길죠? ^_^
그래서 혹시라도

#define CONSOLE(x) CDebugConsole::getConsole().print(x)

라고 선언해서 쓰신다는 분이 있으면, 70점 정도 드리겠습니다....
왜 100점을 못 드리냐면, 저렇게 해서는 뒤에 다중 인자값을 줄 수 없기 때문입니다.
(컴파일은 되지만, %d 의 표현이 안 먹습니다.)
제대로 하기 위해서는

#define CONSOLE CDebugConsole::getConsole().print

이렇게 해주셔야 합니다.
그리고 혹시 디버깅 창이니까...릴리즈 외에 디버깅 용으로만 띄우겠다...이러시는 분들은
#if defined(DEBUG) | defined(_DEBUG)
#define CONSOLE CDebugConsole::getConsole().print
#else
#define CONSOLE(x)
#endif

이렇게 처리해 주시면, 디버깅 시에는 작동하고 디버깅을 하지 않는다면, 깨끗하게 사라집니다.
근데, 어??? 이상하다 왜 CONSOLE(x)라고 썼지?? (x) 붙이지 말라며????
라고 궁금해 하실 분들이 계실껍니다.
그렇다면, 아래의 코드를 봐주세요 ^_^. 

CONSOLE("화면 갱신 %d 번 했네\n", i++);

여기서 릴리즈 모드일때는 CONSOLE의 내용이 없어진다고 생각하지만
만약 #define CONSOLE 로 썼다면, i++는 작동합니다.
#define CONSOLE(x)는 i를 작동하지 않게 합니다. 사실 어느정도 수준으로 남겨 놓느냐는 프로그래머의 선택이지만, 작동하지 않는 것이 좀 더 직관적이죠. i++같은 것들이 남는 다고 생각하면, 상당히 피곤해지기 시작하겠죠.
그리고, #define CONSOLE(x)는 릴리즈 컴파일시에 warning이 생깁니다...음 2개다 문법을 제대로 사용하면, 문제가 없이 쓸 수 있지만, 어떤 것을 선택하냐는 프로그래머 맘이겠죠 ^_^;

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

랜덤함수  (0) 2011.08.13
랜덤함수 C Source  (0) 2011.08.13
도스&콘솔 프로그램 관련(창안띄우기,StdOut, Wait)  (0) 2011.08.13
다중 쓰레드와 C++  (0) 2011.08.13
날짜 스트링을 CTime 으로 변환  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,