C++ 코딩 개발 최적화 팁 9가지, 신입 프로그래머 필독!

C++ 코딩 개발 최적화 팁 9가지, 신입 프로그래머 필독!


1. 파일 경로 \\ 이렇게 \을 두 개 써줌

  C:\\Program Files\\GameTest\\


2. CTime 자료형

long time_t는 1970년 1월 1일부터 time.h에 선언된 long integer type으로서 time()과 mktime()에서 return하는 자료형입니다. time_t의 주소를 매개변수로 보내면 그 변수에 1970년 1월 1일부터 현재 시각 까지의 지나간 시간(초)를 넘겨 주게 됩니다.


1970년 1월 1일 이전의 시간은 나 몰라! 이게 싫으면 COleDateTime을 쓰세요.


여기에는 ParseDateTime() 함수를 이용하여 문자형을 날짜 형으로 바꿀 수 있습니다.


1
2
BOOL ParseDateTime
(LPCTSTR lpszDate, DWORD dwFlags=0, LCID lcid=LANG_USER_DEFAULT)
cs


1
2
3
4
5
6
CString strF, strDate;
COleDateTime strRDate;
 
strF = (LPCSTR)Entry[nIndexItem].RDate;
strDate = strF.Left(4+ L"-" + strF.Mid(4,2+ L"-" + strF.Right(2);
strRDate.ParseDateTime(strDate);
cs

3. MAX_PATH, 260자 한도

파일 경로나 파일명 관련된 코딩을 할 때 흔히 MAX_PATH 매크로를 사용하게 됩니다.


MAX_PATH는 stdlib.h 에 정의되어 있는데 그 크기가 260으로 한정되어 있습니다.

MAX_PATH가 한정하는 길이는 폴더의 길이 및 파일의 길이입니다.


파일명과 폴더명을 포함한 경로를 의미하지는 않습니다. 또 한가지 260을 초과하여 사용하게 되면 중대한 버그가 발생합니다. 또한 윈도우즈를 사용할 때 폴더명을 260자 초과하여 사용하면 에러 발생 컴퓨터가 다운됩니다.


1
2
3
4
5
6
7
8
9
10
// GetCurrentDirectory 파일명을 제외한 경로 얻기
CString CHorseracingOpDoc::GetCurPath(void)
{
 TCHAR pszPathName[_MAX_PATH];
 GetCurrentDirectory( _MAX_PATH, pszPathName);
 return pszPathName;
}
 
// 파일명을 포함한 전체 경로 얻기
   GetModuleFileName( NULL, pszPathName, _MAX_PATH);
cs


4. new 연산자 런타임할당 후 종료 시에는 delete

new 연산자를 사용한 경우 루틴을 빠져나갈 경우 delete를 해 줘야 메모리를 낭비하지 않습니다. free()와 delete의 차이는 소멸자를 호출해주느냐 안 해주느냐의 차이가 있습니다. 소멸자 호출이 필요한 경우 delete를 사용합니다.


new로 생성이 배열 생성을 했을 경우는 배열 delete를 해줘야 합니다. 그러나 런타임 할당이 아닌 기본 배열 생성, 코드 생성 시 할당한 배열은 delete를 해선 안 됩니다.


C++ 코딩 신입 개발 팁[C++ 신입 프로그래머 개발 팁]


5. 난수 발생함수 rand()

난수 발생함수 rand()를 사용하기 위해서는 먼저, seed를 선택해줘야 합니다. seed를 선택하는 방법은 srand() 함수를 호출하는 것인데, 일반적으로 프로그램 내에서는 srand() 함수를 한 번만 불러주어도 충분합니다.


rand()를 부를 때마다, srand()를 부른다면, random number를 얻을 수 없습니다.


1
2
3
사용 예1) 무난한 방법
  srand((unsigned)time(NULL));  // 또는 아래
  srand((unsigned int)time((time_t *)NULL));
cs


1
2
3
4
사용 예2) 1/1000초 단위로 호출하여 대단히 빠르고
시간 간격이 정밀함을 요구할 때는 GetTickCount()를 사용한다.
 
  srand(GetTickCount());    // #include <Windows.h>
cs


그러나 이 방법은 49일 후 오버플로우를 발샐함에 주의를 필요로 합니다. (32비트 unsigned 값이다 보니 약 7주 후 오버플로우 발생)


1
2
사용 예3) 별로 추천하고 싶지 않은 방법 (poor!)
  srand(time(NULL))

cs


그리고 난수 함수는 적은 수에 엄밀하게 랜덤하지 않고, 최대크기 RAND_MAX는 32,767이므로 이 숫자를 넘는 큰 수는 한 번에 랜덤값을 산출할 수가 없습니다.


이보다 큰 수는 좀 머리를 굴려서 사용해야 합니다.


아래는 적은 수에 엄밀하게 랜덤하지 않으므로 그 대책입니다.


1
2
방법1) 무난한 방법
  rand() / (RAND_MAX / N + 1)
cs


1
2
방법2) 실수의 경우
  (int)((double)rand() / ((double)RAND_MAX + 1* N)
cs


1
2
3
4
5
6
7
방법3) [M, N]의 범위를 가지는 random number
  M + rand() / (RAND_MAX / (N - M + 1+ 1)
 
int GetRand(int nStart, int nEnd)
{
   nStart + rand() / (RAND_MAX / (nEnd - nStart + 1+ 1);
cs

6. 자주 쓰고 대단히 유용한 SendMessage() 함수

SendMessage()함수는 윈도우로 명시된 메시지를 보내는 함수로 윈도우 프로시저를 직접 호출하고 메시지가 처리될 때까지 반환하지 않습니다.


함수의 원형(prototype)


LRESULT SendMessage( UNIT messge, WPARAM wParam = 0, LPARAM lParam = 0 );

static LRESULT SendMessage(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);


typedef struct tagMSG


HWND hwnd : 윈도우 핸들( 어떤 윈도우에서 메세지가 발생했나?)

UINT message : 메세지 종류 (보내고자 하는 메시지는 어떤 것?)

WPARAM wParam : 부가적인 정보(32bit)... 키보드에 관한 것

LPARAM lParam : 부가적인 정보(32bit)... 마우스에 관한 것

DWORD time : 메세지 발생 시각

POINT pt : 메세지 발생 좌표


Memory 스택과 큐


Stack - LIFO (Last  In First Out) 후입선출 ... 나중 넣은 것이 먼저 나온다.

Queue - FIFO (First In First Out) 선입선출 ... 먼저 넣은 것이 먼저 나온다.


Stack에 자료를 넣는 것을 '밀어 넣는다' 하여 푸시(push)라고 하고, 반대로 넣어둔 자료를 꺼내는 것을 팝(pop)이라고 합니다.

큐는 put(insert)와 get(delete)을 이용하여 구현됩니다. put는 큐에 자료를 넣는 것을, get은 큐에서 자료를 꺼내는 것을 의미합니다.


front(head)와 rear(tail)는 데이터의 위치를 가리킵니다. front는 데이터를 put 할 수 있는 위치를, rear은 데이터가 있어 get 할 수 있는 위치를 의미합니다.


또, 큐가 꽉 차서 더는 자료를 넣을 수 없는 경우(put 할 수 없는 경우)를 오버플로우(Overflow),

큐가 비어 있어 자료를 꺼낼 수 없는 경우를 언더플로우(Underflow)라고 합니다.


LRESULT 의 의미 => long과 같은 의미


C++ 신입 프로그래머 개발 코딩[C++ 신입 프로그래머 TIP]


SendMessage와 PostMessage의 차이점

 

BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);


두 함수의 인수는 완전히 같습니다. 여기서 Post는 "붙인다", Send는 "보낸다"라고 번역됩니다. PostMessage 함수는 Msg인수로 지정된 메시지를 hWnd 윈도우의 메시지 큐에 집어넣어 윈도우 프로시저에서 이 메시지를 처리하도록 합니다.


메시지를 큐에 넣기만 하고 바로 리턴하므로 메시지를 붙인 후 즉시 다른 작업을 할 수 있지만, 큐에 대기하고 있는 다른 메시지가 있으면 뒤에 붙인 메시지는 곧바로 처리되지 않습니다.


SendMEssage는 WndProc의 case 하나를 호출하는 것과 같이 당장 어떤 일을 하라는 명령이며, PostMessage는 큐에 넣고 한가할 때 어떤 일을 하라는 메세지 신호입니다.


1
2
3
사용 예)
윈도우 종료
 AfxGetMainWnd()->SendMessageW(WM_CLOSE,0,0);
cs

7. UpdateData(TRUE)와 UpdateData(FALSE)

일반적으로 MFC, View Class에서 컨트롤 구현 시 화면 갱신용으로 많이 사용됩니다. MFC, Doc Class에서는 UpdateAllViews(NULL)을 사용하는 것과 같은 기능입니다.


여기서 상기 두 가지는 겉으로 보기는 비슷한 것 같지만, 전혀 반대의 의미가 있습니다.

 

UpdateData(TRUE) - Value형 변수에 사용자가 선택한 값을 대입

UpdateData(FALSE) - Value형 변수의 내용을 화면에 출력


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void COptionDlg::OnEnChangeEditExp()
{
 if (UpdateData(TRUE))
 {
  m_SlideCtrlExp.SetPos(m_nSlideExp);
 }
}
 
void COptionDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
 m_nSlideExp = m_SlideCtrlExp.GetPos();  // GetPos() Slider에 위치를 받음
 UpdateData(FALSE);
 
 CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
 
cs


8. 윈도우 핸들 얻기

핸들(handle)이란 구체적인 어떤 대상에 붙여진 번호이며 문법적으로는 32비트의 정수값입니다.


핸들은 정수값(32bit)


핸들은 운영체제가 만들어 주며 사용자는 가져다가 쓰면 됩니다. 사용자가 직접 핸들을 만들 경우란 없습니다.


같은 종류의 핸들은 중복된 값을 가지지 않습니다. 핸들은 부호 없는 정수형이지만 값의 의미는 없고 단지 구별하기 위해 쓰일 뿐입니다. 윈도우즈 핸들은 접두어 h로 시작됩니다(HWND, HPEN, HBRUSH, HDC).


핸들 구하기


1
2
3
4
5
6
7
8
9
10
방법1) HWND hWnd = ::GetDlgItem(m_hWnd, IDC_LIST_CONTENT);
 
방법2) HWND hWnd = ::FindWindowW(NULL, L"CTestView");
 
방법3) CWnd *pWnd = AfxGetMainWnd(); //윈도우 핸들얻기
    HWND hWnd = pWnd->m_hWnd;
 
방법4) DWORD pID;
    HANDLE hWnd = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
    //OpenProcess(PROCESS_SET_QUOTA, FALSE, dwPID);
cs


인스턴스 정보 구하기


1
HINSTANCE hInst = AfxGetInstanceHandle();
cs


1
2
3
4
5
6
7
8
9
1. 현재 실행중인 프로그램의 ProcessId로 생행중인 프로그램의 핸들 얻기
    HANDLE OpenProcess(
          DWORD dwDesiredAccess,  // access flag
          BOOL bInheritHandle,         // handle inheritance flag
          DWORD dwProcessId          // process identifier
    );
 
    HANDLE m_handle;                   // 대상 프로세스의 핸들
    m_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);  // 프로세스 열기
cs


1
2
3
4
5
6
7
8
2. window name 으로...
    HWND FindWindow(
        LPCTSTR lpClassName,     // pointer to class name
        LPCTSTR lpWindowName  // pointer to window name
    );
 
     HWND hWnd;
     hWnd = ::FindWindow(NULL"TestApp");
cs


개발 C++ 코딩 신입 프로그래머 팁[C++ 신입 프로그래머 개발자 팁]


9. BITMAP Load


 화면DC, 메모리DC 생성

 CClientDC dc(this); CDC dcMem;

 메모리DC가 화면DC와 호환되도록 설정

 dcMem.CreateCompatibleDC(&dc);

 CBitmap 변수 생성

 CBitmap bitmap;

 그 비트맵변수가 그림 로드

 bitmap.LoadBitmap(IDB_BMP);

 메모리DC가 비트맵 변수를 선택

 dcMem.SelectObject(&bitmap);

 화면 DC가 BitBlt(), StretchBlt()로 출력

 BitBlt(8개), StretchBlt(10개)


1
2
3
4
5
6
1:1          축소, 확대
            x y 폭 높이      x y
pDC->BitBlt(0,0,50,50,&dcMem,0,0,SRCCOPY);
pDC->StretchBlt(0,0,200,200,&dcMem,0,0,50,50,SRCCOPY);
...
           dcMem.SelectObject(pOldBitmap); // 메모리DC반환
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
사용 예)
  CPoint pt;                   // x, y  좌표클래스
  CSize size;                 // cx, cy 크기
  CRect rect(pt,size);    // left, top, right, bottom  영역
  CClientDC dc(this);
  CRect rect;
  GetClientRect(&rect);
  dc.SelectObject(GetStockObject(WHITE_PEN));
  //Draw Brush
  CBrush brush, *pOldB;
  brush.CreateSolidBrush(RGB(255,255,255));
  pOldB = dc.SelectObject(&brush);
  ...
                                 dc.SelectObject(pOldB); // 원래의 브러쉬로 반환
  dc.Ellipse(nX-R, nY-R, nX+R, nY+R);
 
  //Draw Pen
  CPen pen, *pOldP;
  pen.CreatePen(PS_SOLID, m_nWidth, m_crPen);
  pOldP = dc.SelectObject(&pen);
  ...
                    pDC->SelectObject(pOldP); // 펜반환  dc.SelectObject(pOldP);
cs


출처 1 - 윤성우의 열혈강의 C++ 프로그래밍

출처 2 - [MFC] 간단하지만 중요한 사실 10가지 ( 팁 필수 자료) [클릭]

C++ 코딩 개발 최적화 팁 9가지, 신입 프로그래머 필독!

댓글(0)

Designed by JB FACTORY