모르면 고생하는 VC++ 팁
컨텐츠 정보
- 24,388 조회
- 0 추천
- 목록
본문
스레드를 사용하는 프로그램 디버그시 OS가 멈추는 현상
XP에서 스레드를 사용하는 프로그램을 디버깅하다 보면 자주 OS가 멈춰버려서 리부팅까지 해야 되는 상황이 자주 발생합니다. 이 때문에 98이나 2000 에서 디버깅을 하기도 했는데 VC++ 6.0과 XP가 충돌하는 것으로도 의심을 했었지만 VC++2005 에서도 동일한 문제가 생긴다고 합니다.
그래서 검색을 해보니 원인은 IME 쪽 버그라고 합니다.
해결방법은 제어판 --> 국가 및 언어 옵션 --> 언어 탭 --> 자세히... --> 고급 --> 고급 텍스트 서비스 사용 안 함 을 체크하고 리부팅을 합니다.
VC++의 메모리 누수 (Memory Leak) 탐지 기능 사용하기
보통 디버깅을 하다보면 메모리 릭이 발생했다는 메시지가 출력되지만 어디에서 현상이 발생했는지는 표시해 주지 않습니다. 다른 유틸리티를 사용해 보기도 했지만 가끔 프로그램에 충돌이 생겨 디버깅을 할 수 없었습니다.
이런 경우에 VC++에 내장된 메모리 누수 탐지 기능을 사용해서 현상이 발생된 소스 파일의 위치를 표시하도록 할 수 있습니다. 원리는 new 나 malloc 등의 함수를 새로 정의해 메모리를 할당할 때 소스 파일의 위치를 기억해 두었다가 프로그램 종료시 해제되지 않은 메모리의 위치를 표시하도록 하는 것입니다.
소스 파일명을 나타내는 마크로 __FILE__와 라인 번호를 나타내는 마크로 __LINE__ 가 사용됩니다.
(1) MFC를 사용하는 경우
먼저 stdafx.h 파일에서 다른 include 문 보다 제일 상위에 다음 선언문을 추가 합니다.
#ifdef _DEBUG#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures
#define _INC_MALLOC // exclude standard memory alloc procedures
#endif
_CRTDBG_MAP_ALLOC 은 crtdbg.h 파일에서 new 등을 새로 정의하도록 사용됩니다.
그리고 프로그램 초기에 아래 함수를 추가합니다.
#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif
stdafx.h 파일을 사용하지 않는 소스 파일의 경우 (Pre compiled header 기능을 사용하지 않는 경우)는 기존 메모리 할당 함수를 사용하게 되므로 이 기능이 지원되지 않게 됩니다.
만일 stdlib.h 파일에서 컴파일 에러가 발생하는 경우는 다음을 시도해 봅니다.
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures
#define _INC_MALLOC // exclude standard memory alloc procedures
#endif
(2) MFC를 사용하지 않는 경우
crtdbg.h 파일이 자동으로 추가 되지 않으므로 소스 파일에 crtdbg.h 를 추가해야 합니다.
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include [crtdbg.h] <-- 수정 필요 :-)
#endif
마찬가지로 프로그램 초기에 아래 함수를 추가 합니다.
#ifdef _DEBUG
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif
(3) 링크에러가 발생하는 경우
nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in StdAfx.obj
위와 같은 링크 에러가 발생하게 되면 임시 방편으로 아래와 같이 강제로 링크하도록 합니다.
Project Settings --> Link --> Customize --> Force file output 항목 체크
이는 Project options에 /FORCE 플래그를 추가 하는 것과 동일 합니다.
다른 링크 에러의 경우는 아래 사이트를 참조합니다.
http://support.microsoft.com/kb/148652
참고: http://www.codeproject.com/KB/cpp/MemLeakDetect.aspx
static 라이브러리 작성시 주의사항
static 라이브러리를 작성해 application에 링크하려다 보면 LIBCD.lib 등의 링크 에러가 발생합니다. 이것은 static library 위저드와 application 위저드가 Code Generation 옵션을 서로 다르게 생성하기 때문입니다.
해결 방법은 Project Settings --> C/C++ --> Code Generation --> Use run-time library --> Debug Multithreaded XXX 식으로 application에 사용된 속성과 맞춰줘야 합니다.
마찬가지로 라이브러리를 사용하는 프로그램 컴파일시 already defined... LIBC.lib, LIBCMT.lib 등의 에러 메시지가 출력된다면 사용중인 라이브러리의 일부가 프로그램과 다른 Run-time library 로 컴파일 된 것이기 때문에 이 문제를 수정해 줘야 합니다.
LIBC.lib 는 single-thread 용이고 LIBCMT.lib 는 multithread 용이며 LIBCD.lib 는 Debug용 single-thread 입니다.
디버그시 변수값 보기
사용자 지정 구조체등의 값이 표시되지 않을 때나 크기가 아주 큰 변수의 경우 메모리 뷰를 띄워서 볼 수도 있지만 불편하다. 이 경우 변수, 10 (앞의 10 바이트만 표시) 형식으로 입력하면 된다.
원하는 데이터 형으로 보고 싶은 경우에는 (형변환자)변수 형식으로 입력한다.
텍스트를 컬럼으로 선택하기
- 텍스트를 라인으로 선택하지 않고 컬럼으로 선택하려면 ALT + 마우스 드래그, 또는 ALT+SHIFT+방향키를 사용한다.
칸을 맞춰놓은 경우 중간에 불필요한 것을 삭제하거나 끼워 넣을 경우 일일히 타이핑하지 않아도 되므로 편리하다.
무료 윈도우 컴파일러 사용하기
- 코드프로젝트의 다음 기사를 참고하여 VC++ 2005 Express 버전을 설치하고 MFC대신에 WTL을 개발 프레임워크로 사용한다.
Using WTL with Visual C 2005 Express Edition
http://www.microsoft.com/express/2005/download/default.aspx
- 무료 리소스 편집기로는 ResEdit 을 추천한다.
- VC++ 2005 Express에 리소스편집기 등록 방법: RC파일을 선택하고 팝업메뉴에서 Open With...를 클릭한다. [Add...] 버튼으로 리소스 편집 프로그램을 등록 후 [Set as Default]를 클릭한다.
- VC Express 버전에서 MFC 프로그램 컴파일하기
- win32 : 간단한 Win32 래퍼 클래스를 원한다면....
들여쓰기 자동 정렬하기
- 입수한 소스가 들여쓰기가 제대로 안돼 있어서 읽기 불편한 경우 다음과 같은 방법으로 자동정렬 할 수 있다.
우선 정렬할 부분을 선택하고 SHIFT + TAB 키를 몇 번 눌러 불필요한 불필요한 공백 문자를 제거한다.
그리고 ALT+F8 을 누르면 자동으로 들여쓰기를 맞춰준다.
추가된 클래스가 클래스위저드에서 보이지 않을 때
보통은 클래스위저드 파일(.clw)을 삭제하고 갱신해 준다.
이렇게 해도 클래스가 보이지 않으면 다음 내용이 소스파일에 있는지 확인하고 없으면 추가해 준다.
헤더 파일에는 다음 내용이 들어 있어야 한다.
// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyWnd) //}}AFX_VIRTUAL // Generated message map functions protected: //{{AFX_MSG(CMyWnd) //}}AFX_MSG DECLARE_MESSAGE_MAP()그리고 소스 파일에는 다음 내용이 있어야 한다.
BEGIN_MESSAGE_MAP(CMyWnd, CWnd) //{{AFX_MSG_MAP(CMyWnd) //}}AFX_MSG_MAP END_MESSAGE_MAP()위 내용이 없는 경우 클래스위저드에 나타나지 않는다.
편집한 리소스가 갱신이 안된 경우
열심히 ICON 파일을 편집해서 저장했는데 VC6에서 열어보면 수정하기 전의 내용이 보여 당황하는 경우가 있다.
이 때는 *.aps 파일을 삭제해 준다. 이 놈이 리소스 데이터를 캐시 해두는 파일로 보인다.
그래서 실제 리소스 파일에서 읽어오지 않고 캐시된 데이터를 읽어 오므로 이전 데이터가 보이는 것이다.
소스 코드를 배포하는 경우에도 *.aps, *.plg, *.ncb, *.opt 및 *.obj 파일 등은 불필요하고 용량만 많이 차지 하므로 삭제하고 배포하도록 해야 한다.
GetTickCount 사용시 주의
간단히 시간 간격을 측정하기 위해 GetTickCount 를 여러 공개 소스에서 사용하지만 실제 프로그램에서는 사용하지 않는 것이 좋다.
리턴값이 32비트로 시스템 시작후 49.7 일 마다 초기화 되는 값이며 특히 서버 프로그램에서 잘못 사용하면 무한루프에 빠질 수 있다.
다른 간단한 방법으로 _ftime을 이용해 경과 시간을 구할 수 있다.
#include [sys/timeb.h]
DWORD ticks;
struct _timeb from, now;
_ftime(&from);
.........
_ftime(&now);
ticks = (DWORD)difftime(now.time, from.time) * 1000;
if(from.millitm == 0)
ticks += now.millitm;
else
ticks += now.millitm + (1000 - from.millitm);
PostMessage 사용시 주의
PostMessage 는 SendMessage 와 달리 프로그램이 메시지를 빈번히 처리해서 메시지큐가 full 인 경우에는 처리되지 않는다. 따라서 중요한 처리의 경우는 리턴값을 확인해야 한다.
화면 갱신시 깜박임 없에기
클라이언트 영역에 그래픽 작업이나 컨트롤을 올릴 때 화면이 깜박이는 문제를 없에려면,
(1) Memory DC를 사용한다.
화면에 직접 그릴 경우는 배경 칠하고 위에 다른 것을 그리면 이것이 눈에 띄게 된다. CreateCompatibleDC를 이용해 메모리DC에 모두 그려준 다음 BitBlt를 이용해 한꺼번에 화면에 복사해 주면 깜박임이 없어 진다.
(2) OnEraseBkgnd (WM_ERASEBKGND) 처리를 막는다.
윈도우는 기본적으로 화면 갱신시 WM_ERASEBKGND로 먼저 배경을 지우고 WM_PAINT로 화면을 그린다. 보통 배경을 흰색으로 채우기(지우기) 때문에 깜박임이 발생한다. OnEraseBkgnd 를 바로 return TRUE; 로 하여 처리를 막으면 깜박임이 없어진다.
(3) Parent 윈도우가 있는 경우
메인 프레임이 아닌 일반 윈도우를 Parent 윈도우로 갖고 있는 경우 Parent 윈도우를 먼저 그리고 Child 윈도우를 그리기 때문에 Child 윈도우에서 깜박임이 발생한다. 이 때는 Parent 윈도우의 속성에 WS_CLIPCHILDREN 을 추가 해주면 Parent 영역 갱신시 Child 영역은 제외하기 때문에 깜박임이 없어진다.