2008년 10월 31일 금요일

MFC가 제공하는 List Class - CStringList

■ MFC가 제공하는 List Class - CStringList



※ MFC 가 제공하는 List Class
  - 양방향 포인터를 가지는 이중 연결 리스트(Doubly-Linked List)
  - 리스트의 처음 부분을 가리키는 포인터(Head) 와 끝 부분을 가리키는 포인터(Tail)가 있다.
    따라서 어느 방향으로든 순환하는 것이 가능하다.

  MFC가 제공하는 List Class
  ① 템플릿 클래스 (Template Class)
  ② 비 템플릿 클래스 (Nontemplate Class)



① 템플릿 클래스 (Template Class)
  - afxtempl.h 헤더파일 필요.
  - 원하는 종류의 데이터 타입을 프로그래머가 결정
  - 비 템플릿 클래스가 제공하는 모든 기능을 구현할 수 있기 때문에 템플릿 클래스 사용을 권장.










 클래스 이름 데이터 타입 사용 예
 CList프로그래머가 결정  CList<CPoint, CPoint &> list;


② 비 템플릿 클래스 (Nontemplate Class)  - afxcoll.h 헤더 파일이 필요.
  - 자주 사용하는 데이터 타입을 곧바로 사용할 수 있다.


















 클래스 이름 데이터 타입 사용 예
 CObList CObject 포인터 CObList list;
 CPtrList void 포인터 CPtrList list;
 CStringList CString CStringList list;

 CObList, CPtrList, CStringList 는 제공하는 멤버 함수의 이름과 사용법이 동일 하므로 하나의 클래스만 배워두면
다른 모든 클래스에도 동일하게 적용할 수 있다.

  - 멤버 함수
    CStringList : CStringList 객체 생성.
    GetHead : 리스트의 헤드 값을 돌려준다.   
    GetTail : 리스트이 테일 값을 돌려준다.
    RemoveHead : 리스트 헤드 값을 제거.
    RemoveTail : 리스트 테일 값을 제거.
    RemoveAll : 리스트의 모든 원소를 제거
    AddHead :  한 원소(또는 다른 리스트의 모든 원소들)을 리스트의 헤드에 붙인다.(새로운 헤드를 만는다는 뜻.)
    AddTail : 한 원소(또는 다른 리스트의 모든 원소들)을 리스트의 테일에 붙인다.(새로운 헤드를 만는다는 뜻)
    GetHeadPosition :  리스트의 헤드 원소 위치를 반환.
    GetTailPosition : 리스트의 테일 원소 위치를 반환.
    GetNext : 반복할 때 다음 원소를 얻는다
    GetPrev : 반복할 때 이전 원소를 얻는다.
    GetAt : 주어진 위치에서 원소를 얻는다
    SetAt :  주어진 위치에서 원소를 넣는다. 
    RemoveAt : 리스트에서 특정한 위치에 있는 원소를 제거.
    InsertBefore : 주어진 위치 이전에 새 원소를 삽입.
    InsertAfter : 주어진 위치 이후에 새 원소를 삽입.
    Find : 포인터 값에 의해 지정된 원소의 위치를 얻는다.
    FindIndex : 0부터 시작하는 인덱스를 기준으로 원소의 위치를 얻는다.
    Getcount : 리스트에서 총 원소의 개수를  구한다.
    IsEmpty : 비어 있는 리스트인지 테스트한다.



1. CStringList 사용 예
  - 리스트의 생성과 초기화




char *szFruits[] = {
    "사과",
    "딸기",
    "포도",
    "오렌지",
    "자두"
};

CStringList list;
for (int i = 0; i < 5; i++)
    list.AddTail(szFruits[i]);

  - 리스트 순환POSITION pos = list.GetHeadPosition();
while(pos != NULL){
    CString string = list.GetNext(pos);
    cout << (LPCTSTR)string << endl;
}
cout << endl;

// 리스트 제일 뒤에서 출발하여 순환한다.
pos = list.GetTailPosition();
while(pos != NULL){
    CString string = list.GetPrev(pos);
    cout << (LPCTSTR)string << endl;
}


    ※ POSITION 타입의 변수은 pos는 GetNext(), GetPrev() 함수를 호출할 때마다 값이 바뀐다.


  - 리스트 항목 삽입과 삭제pos = list.Find("포도");
list.InsertBefore(pos, "살구");
list.InsertAfter(pos, "바나나");
list.RemoveAt (pos);

// 항목 삽입과 삭제 후 결과를 확인한다.
pos = list.GetHeadPosition();
while(pos != NULL){
    CString string = list.GetNext(pos);
    cout << (LPCTSTR)string << endl;
}



##

Debug 용 함수

Debug 용 함수




 대학교 4년동안 Visual Studio를 사용하면서 왜 디버그에 대한 관심이 없었을까?
printf() 를 너무 사랑했었고, Windows 프로그래밍으로 넘어오면서 CString과 AfxMessageBox()를
첩으로 두었다... 이제 학교생활은 끝났다. 디버그에대해 관심을 갖자.

                - TRACE
                - ASSERT
                - AfxDebugBreak()
                - VERYFY
                - ::afxDump

* 디버그용 매크로들은 "_DEBUG" 가 정의 되어 있어야 한다.
* 디버그 모드로 빌드하면 자동으로 "_DEBUG" 가 정의 된다.
* 릴리즈 모드로 컴파일시 빠짐.


1. TRACE
   - 디버거의 Output Window 에 출력
   - ATLTRACE : ATL 매크로도 동일 동작
   - TRACE0(),TRACE1(), TRACE2(), ...  참조
   - 예 
                int x = 1;
                int y = 16;
                float z = 32.0;
                TRACE( "This is a TRACE statement\n" );
                TRACE( "The value of x is %d\n", x );
                TRACE( "x = %d and y = %d\n", x, y );
                TRACE( "x = %d and y = %x and z = %f\n", x, y, z );
  

사용자 삽입 이미지
   - 기본적으로 printf()와 비슷한 형식을 취하기 때문에 CString 객체는 출력할 수 없음  
   - TRACE() 사용시 주의 사항
      a. 여러 변수 값을 찍을 경우




2. ASERT
   - 인자의 논리값이 false인 경우 다이얼로그 창을 띄우며 프로그램을 멈춤
   - "재시도" 선택 시 디버거 실행 : AfxDebugBreak() 호출
   - 코드 예
                bool bRet = false;
                ASSERT(bRet);
 
사용자 삽입 이미지


3. AfxDebugBreak()
   - 매크로가 아니라 함수 이다.
   - hard-coding breakpoint 라고 함.
   - Visual Studio 에서 F9를 눌러 breakpoint를 넣는게 아니라,
     코드 안에서 직접 '_asm int 3' 하고 breakpoint를 넣은 것.
   - 실제로 F9 로 breakpoint를 설정하면 해당 위치의 코드 첫 Byte를 그 코드로 대체시킴.




4. VERIFY
   - 인수의 결과가 참인지 거짓인지에 따라 프로그램을 종료 할지 계속 수행할지
    판별해 주는 매크로 이다.

   - 인수의 표현식에는 0, 또는 0이 아닌 수를 리턴하는 판별식이 들어가야 한다.
   - 0이 아닌 리턴값을 갖으면 VERIFY() 매크로는 아무것도 하지 않는다.
   - 0 리턴값을 갖으면 에러 메시지 출력후 프로그램을 중단 한다.




5. ::afxDump - C++ 의 cout 처럼 사용할 수 있다.
 - 사용 예

CString str;
str.Format(_T("afxDump"));
::afxDump << str << "\n";





@

:: (스코프 연산자)




C++ 코드에서 많이 볼 수있는 :: (스코프) 연산자



기능1. 동일 소스의 중첩관계에서 가장 외곽에 있는 값을 의미

int iAbc= 128;

if (iAbc > 0) {
   int iAbc = 256;

   if (::iAbc < 200) {
      // ::iAbc 는 가장 외곽에 있는 iAbc 값이다.(128 값을 갖는)
   }
}



기능2. class 에서 멤버함수 접근할때.(가장 흔한 경우)


기능3. MFC 프로그램 작성중 Win32 API 함수를 호출할 때       즉, ::SecureZeroMemory(...)  함수 호출
       - 전역 선언인 Win32 API 함수를 호출
       - 클래스 내의 사용자가 정의한 멤버 함수와 이름이 겹칠경우를 대비하여 호출 한다고 한다.
         코딩할때 이름이 겹쳐서 :: 연산자를 사용하여 호출 하는 경우보다  해당 함수는 "Win32 API 함수를 호출한다"
         라는 것을 명시적으로 보여주는 역할이 더 클것 같다. 소스를 다른 사람이 봐도 쉽게 이해할 수 있도록.

2008년 10월 20일 월요일

[MFC_Debug] error C2664: 'MessageBoxW' : 매개 변수 2을(를) 'const char[11]'에서 'LPCWSTR'(으)로 변환할 수 없습니다.



■ Source

#include <windows.h>

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance,
                                LPSTR lpCmdLine, int nShowCmd)
{
       MessageBox(NULL, "안녕하세요", "안녕", MB_OK);

       return 0;
}


■ Error Message :
error C2664: 'MessageBoxW' : 매개 변수 2을(를) 'const char [11]'에서 'LPCWSTR'(으)로 변환할 수 없습니다.


■ 발생 원인
 프로젝트 속성의 문자집합에서  "유니코드 문자 집합 사용" 으로 되어있기 때문이다.
MessageBox() 함수 안에 2번째, 3번째 매개변수가 유니코드 형식을 사용하지 않기 때문.


■ 해결 방법
1. 프로젝트 옵션에서 문자집합 옵션을 바꿔준다.
 "멀티 바이트 문자 집합 사용" 으로 선택

cf) "유니코드 문자 집합을 사용" : 유니코드 사용
    "멀티 바이트 문자 집합 사용" : ANSI 사용


2. MessageBox() 함수 대신에 MessageBoxA() 함수를 사용해 준다.

2008년 10월 18일 토요일

CString 데이터를 char *형으로 변환에 대하여(주의할 점)


CString 데이터 값을 char *형 값으로 이용하기 위해

           CString str;

           str_T("Hellow");
           char *ss = CPSTR(CPCTSTR(str));


위와 같은 방법을 보통 이용한다.
물론 나도 그렇게 알고 있었는데...

일회성적으로 사용한다면 당장은 큰 문제를 갖지는 않는다.
하지만 그렇게 장기적 치명적 버그를 만들 가능성이 있다.

CString 객체... 생각보다 간단하게 구현된게 아니다.

CString 은 메모리 관리 효율과, 인자전달의 효율적 사용을 위해
"공유버퍼" 를 사용한다.

자세히 설명하긴 좀 길어지고
첨부 파일을 첨부한다.
(나도 가르침을 받은 파일인데... 허락 안받고 공개해도 되는 것인지는... 짤리진 않겠지 -_-)

cfile24.uf.12170B3E50AEC14E17566F.pdf


CString 사용시 주의사항!!
1. 매개 변수를 CString을 넘길때 Reference 타입으로 넘기면 효울적
2. char * 형 변환시 (LPTSTR)(LPCTSTR) 사용 금지
3. GetBuffer() 호출 후, CString 멤버 함수를 호출하기 전에 ReleaseBuffer()를 꼭 호출할 것