반응형


static_cast와 dynamic_cast의 속도 비교를 해 보았다.



아래는 실험한 코드와 결과 화면이다. debug로 테스트 한 결과다.





  1. // cmd.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. class object  
  7. {  
  8. public:  
  9.     virtual void print() { cout << "object" << endl; }  
  10.     virtual void copy(TCHAR* a) {}  
  11. };  
  12.   
  13. class AAA : public object  
  14. {  
  15. public:  
  16.     virtual void print() { cout << "AAA" << endl; }  
  17.     void copy(TCHAR* a) { _tcscpy( str, a ); }  
  18.       
  19. private:  
  20.     TCHAR str[1024];  
  21. };  
  22.   
  23. int _tmain(int argc, _TCHAR* argv[])  
  24. {  
  25.     object* mTestObject = new AAA;  
  26.   
  27.     CCheckTime t; t.start();  
  28.       
  29.     for(DWORD i=0; i<10000000; i++)  
  30.         static_cast<AAA*>(mTestObject)->copy("KOREA");  
  31.   
  32.     cout << "static_cast : " << t.end() << "ms" << endl;  
  33.     t.start();  
  34.   
  35.     for(DWORD i=0; i<10000000; i++)  
  36.         dynamic_cast<AAA*>(mTestObject)->copy("KOREA");  
  37.   
  38.     cout << "dynamic_cast : " << t.end() << "ms" << endl;  
  39.   
  40.     delete mTestObject;  
  41.     return 0;  
  42. }  





2배 정도 차이나는걸로 보이는데 릴리즈로 컴파일하게 되면 더 차이가 날 듯 하다.

아마도 검사하는 부분이나 기타 설정부분에서 dynamic_cast가 하는 일이 많으니 이런 일이 생기는듯 하다..


아마도 상속관계를 확실히 알고 있다면 dynamic_cast보다는 static_cast로 작성하는것이 코드 구동 시간에서도 최적화에서도 더 나은 선택, 반드시 선택해야 될듯 하다.


반응형
반응형
http://mnlt.tistory.com/131

ListControl은 MFC에서 굉장히 유용히 쓰이는 컨트롤입니다.
해당 컨트롤에서 직접 원하는 위치를 즉석 수정하기 위한 컨트롤을 만들었습니다.

아마 그냥 유용하게 쓰일듯 싶기도 해서 포스팅.

EditListCtrl.h
  1. #pragma once  
  2.   
  3.   
  4. // CEditListCtrl  
  5.   
  6. class CEditListCtrl : public CListCtrl  
  7. {  
  8.     DECLARE_DYNAMIC(CEditListCtrl)  
  9.   
  10. public:  
  11.     CEditListCtrl();  
  12.     virtual ~CEditListCtrl();  
  13.   
  14. protected:  
  15.     DECLARE_MESSAGE_MAP()  
  16.   
  17. public:  
  18.     virtual BOOL PreTranslateMessage(MSG* pMsg);  
  19.     afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);  
  20.   
  21.     // 초기화 함수.  
  22.     void Init(void);  
  23.   
  24.     // CEditListCtrl 을 사용하는 Dialog 의 OnOK 함수가 호출될때 호출해야 한다.  
  25.     void OnOK(void);  
  26.   
  27.     // List 값을 바꾼다.  
  28.     BOOL SetText(CString _val, int _row, int _col);  
  29.   
  30. protected:  
  31.     // ListCtrl 을 클릭했을때 nItem 저장될 변수. (Row)  
  32.     int m_nItem;  
  33.   
  34.     // ListCtrl 을 클릭했을때 nSubItem 저장될 변수 (Col);  
  35.     int m_nSubItem;  
  36.   
  37.     // 현재 포커스가 어딘지 확인하는 변수  
  38.     HWND m_hFocus;  
  39.   
  40.     bool m_bInit;  
  41.   
  42.     HWND _GetEditHwnd(void);  
  43.     HWND _GetListHwnd(void);  
  44.     HWND _GetParentHwnd(void);  
  45. };  


EditListCtrl.cpp
  1. // EditListCtrl.cpp : 구현 파일입니다.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include "TestApp.h"  
  6. #include "EditListCtrl.h"  
  7.   
  8.   
  9. // CEditListCtrl  
  10.   
  11. IMPLEMENT_DYNAMIC(CEditListCtrl, CListCtrl)  
  12.   
  13. CEditListCtrl::CEditListCtrl()  
  14. : m_nItem(0), m_nSubItem(0)  
  15. , m_bInit(false)  
  16. , m_hFocus((HWND)0)  
  17. {  
  18.   
  19. }  
  20.   
  21. CEditListCtrl::~CEditListCtrl()  
  22. {  
  23. }  
  24.   
  25. BEGIN_MESSAGE_MAP(CEditListCtrl, CListCtrl)  
  26.     ON_NOTIFY_REFLECT(NM_CLICK, &CEditListCtrl::OnNMClick)  
  27. END_MESSAGE_MAP()  
  28.   
  29.   
  30.   
  31.   
  32. // CEditListCtrl 메시지 처리기입니다.  
  33.   
  34. BOOL CEditListCtrl::PreTranslateMessage(MSG* pMsg)  
  35. {  
  36.     if(m_hFocus != (HWND)0)  
  37.     {  
  38.         HWND hFocus = ::GetFocus();  
  39.   
  40.         // Edit 가 Focus를 잃으면.  
  41.         if(m_hFocus != hFocus)  
  42.         {  
  43.             OnOK();  
  44.         }  
  45.     }  
  46.       
  47.   
  48.     return CListCtrl::PreTranslateMessage(pMsg);  
  49. }  
  50.   
  51. void CEditListCtrl::Init(void)  
  52. {  
  53.     if(m_bInit) return;  
  54.   
  55.     SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);  
  56.     ::ShowWindow(_GetEditHwnd(), SW_HIDE);  
  57.   
  58.     m_bInit = true;  
  59. }  
  60.   
  61.   
  62. // Return 키가 눌렸을때 호출하기 위한..  
  63. void CEditListCtrl::OnOK(void)  
  64. {  
  65.     CWnd* pWnd = GetFocus();  
  66.   
  67.     if(_GetEditHwnd() == pWnd->GetSafeHwnd() ||  
  68.         _GetEditHwnd() == m_hFocus)  
  69.     {  
  70.         // EditCtrl로 부터 Text를 얻어온다.  
  71.         wchar_t cText[255];  
  72.         ZeroMemory(cText, 255);  
  73.         ::GetWindowText(_GetEditHwnd(), cText, 255);  
  74.         CString cStrText(cText);  
  75.   
  76.         // 얻어온 텍스트를 ListCtrl 에 적용시킨다  
  77.         if(SetText(cStrText, m_nItem, m_nSubItem) == FALSE)  
  78.             return;  
  79.   
  80.         // EditCtrl의 Focus를 죽인다.  
  81.         ::SendMessage(_GetEditHwnd(), WM_KILLFOCUS, 0, 0);  
  82.         ::ShowWindow(_GetEditHwnd(), SW_HIDE);  
  83.         ::SetFocus(pWnd->GetSafeHwnd());  
  84.   
  85.         // ListCtrl의 SelectionMark를 지정한다.  
  86.         SetSelectionMark(m_nItem);  
  87.     }  
  88.   
  89.     m_hFocus = (HWND)0;  
  90. }  
  91.   
  92. BOOL CEditListCtrl::SetText(CString _val, int _row, int _col)  
  93. {  
  94.     return SetItemText(_row, _col, _val);  
  95. }  
  96.   
  97. void CEditListCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)  
  98. {  
  99.     Invalidate();  
  100.   
  101.     LPNMITEMACTIVATE pNMITEM = (LPNMITEMACTIVATE) pNMHDR;  
  102.     m_nItem = pNMITEM->iItem;  
  103.     m_nSubItem = pNMITEM->iSubItem;  
  104.   
  105.     // 선택된 지점이 올바르지 않을시...  
  106.     if(m_nSubItem == 0 || m_nSubItem == -1 || m_nItem == -1)  
  107.         return;  
  108.   
  109.     // 선택된 SubItem의 Text를 CEdit 에 넣어주기 위한 변수  
  110.     CString cStrText = GetItemText(m_nItem, m_nSubItem);  
  111.   
  112.     CRect rtSubItem, rtListCtrl, rtDlg;  
  113.     // SubItem 의 Rect를 얻어온다.  
  114.     if(GetSubItemRect(pNMITEM->iItem, pNMITEM->iSubItem, LVIR_BOUNDS, rtSubItem) == FALSE)  
  115.         return;  
  116.   
  117.     // ListControl 의 Window Bounds 를 얻어온다.  
  118.     ::GetWindowRect(_GetListHwnd(), &rtListCtrl);  
  119.   
  120.     // Parent Dialog 의 Windows Bounds 를 얻어온다.  
  121.     ::GetWindowRect(_GetParentHwnd(), &rtDlg);  
  122.   
  123.     // Dialog에 위치한 ListCtrl의 left & top 위치를 구한다.  
  124.     int nThisLeft = rtListCtrl.left - rtDlg.left;  
  125.     int nThisTop = rtListCtrl.top - rtDlg.top;  
  126.   
  127.     // EditCtrl의 위치를 변경해준다.  
  128.     ::SetWindowPos(  
  129.         _GetEditHwnd(),   
  130.         HWND_TOP,  
  131.         nThisLeft + rtSubItem.left + 7,  
  132.         nThisTop + rtSubItem.top + 4,  
  133.         rtSubItem.Width() - 7,  
  134.         rtSubItem.Height() - 4,  
  135.         NULL);  
  136.   
  137.     // EditCtrl Show  
  138.     ::ShowWindow(_GetEditHwnd(), SW_SHOW);  
  139.     ::SetFocus(_GetEditHwnd());  
  140.   
  141.     // SubItem 위치에 외각선을 그려준다.  
  142.     ::Rectangle(::GetDC(_GetListHwnd()), rtSubItem.left, rtSubItem.top - 1, rtSubItem.right, rtSubItem.bottom);  
  143.   
  144.     // EditCtrl 에 선택한 List의 Text 를 넣어준다.  
  145.     ::SetWindowText(_GetEditHwnd(), cStrText);  
  146.   
  147.     // 삽입한 Text의 마지막에 포커스를 맞춰주고 Mark한다.  
  148.     int nSel = cStrText.GetLength();  
  149.     ::SendMessage(_GetEditHwnd(), EM_SETSEL, LOWORD(nSel), HIWORD(nSel));  
  150.   
  151.     // Focus를 잃었을 경우 ListCtrl에 적용시키기 위해 저장  
  152.     m_hFocus = _GetEditHwnd();  
  153.     Invalidate();  
  154.   
  155.     *pResult = 0;  
  156. }  
  157.   
  158.   
  159. HWND CEditListCtrl::_GetEditHwnd(void)  
  160. {  
  161.     return ::GetDlgItem(GetParent()->GetSafeHwnd(), IDC_EDIT_CAM_ATTR);  
  162. }  
  163.   
  164. HWND CEditListCtrl::_GetListHwnd(void)  
  165. {  
  166.     return GetSafeHwnd();  
  167. }  
  168.   
  169. HWND CEditListCtrl::_GetParentHwnd(void)  
  170. {  
  171.     return GetParent()->GetSafeHwnd();  
  172. }  



이 컨트롤을 가지는 Dialog Class의 PreTranslateMessage 부분 혹은 OnOK 부분 (Return키 작동시를 위한)에
현재 포커스가 ListCtrl 혹은 EditCtrl 일 경우 CEditListCtrl 의 OnOK 함수를 호출해야 합니다.

  1. CTestDlg::OnOK()  
  2. {  
  3.     int id = GetFocus()->GetDlgCtrlID();  
  4.     if(id == IDC_LIST_EDITLISTCTRL || id == IDC_EDIT_EDITLISTCTRL)  
  5.         m_editListCtrl.OnOK()  
  6. }  


이정도가 되겠습니다.


반응형
반응형

이미 CMFCShellListCtrl 내부에서 더블클릭 이벤트를 처리하고 있기 때문입니다.

 

CMFCShellListCtrl 에서 상속받은 MyShellListCtrl 클래스 하나 만드시고 

 

NM_DBLCLK Notify Reflect 이벤트 핸들러 등록하신 다음 거기서 처리해보세요.

 

ON_NOTIFY_REFLECT(NM_DBLCLK, &MyShellListCtrl::OnNMDblclk)

 

MyShellListCtrl::OnNMDblclk 안에서는 다음 코드를 한번 불러줘야 원래 동작이 실행됩니다.

 

CMFCShellListCtrl::OnDblClk(pNMHDR, pResult);






http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=511226&ref=511179


1. MFC를 사용하시려면

  다이얼로그 편집창에서 Ctrl+W 눌러서 클래스위저드를 실행하구요

  Member varible 탭에서 IDC_LIST_USER 을 더블클릭하여

  멤버이름을 m_ListUser로 카테고리를 Control로 지정하고 확인버튼을 눌러 닫습니다.

 

  ----소스코드 수정----

//    HWND hWnd1 =  ::GetDlgItem (m_hWnd,IDC_LIST_USER);

    LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE) pNMHDR;

    RECT rect;

    //get the row number

    int nItem = temp->iItem;

    //get the column number

    

    int nSubItem = temp->iSubItem;

    if(nSubItem == 0 || nSubItem == -1 || nItem == -1)

        return ;

    //Retrieve the text of the selected subItem from the list

    CString str = m_ListUser->GetItemText(nItem ,nSubItem);

 

2. API로 코딩하시려면

    GetItemText 대신에 ListView_GetItemText 함수를 사용하셔야 합니다.

 

   ---- 소스코드 수정----

  HWND hWnd1 =  ::GetDlgItem (m_hWnd,IDC_LIST_USER);

    LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE) pNMHDR;

    RECT rect;

    //get the row number

    int nItem = temp->iItem;

    //get the column number

    

    int nSubItem = temp->iSubItem;

    if(nSubItem == 0 || nSubItem == -1 || nItem == -1)

        return ;

    //Retrieve the text of the selected subItem from the list

    CString str;

    ListView_GetItemText(hWnd1,nItem ,nSubItem, str, 255);

 

둘 중에서 편한방법으로 코딩하세요...^^



반응형
반응형

http://sehwa4444.egloos.com/2728018



다이얼로그에는 OnIdle은 없지만 내부적으로 UI업데이트를 위한 WM_KICKIDLE 메시지를 가지고 있다
WM_KICKIDLE 메세지는 UNDOCUMENT 메세지로 idle상태일때 보내지는 메세지며 위자드에서 지원하지 않기 때문에 직접 넣어줘야한다.

 
// -- DMyDlg.h --

#include <afxpriv.h>


CMyDialog : public CDialog
{
...
protected:
   ... // other message handler
   afx_msg LRESULT OnKickIdle(WPARAM wParam, LPARAM lParam);
   ...
};

 


// -- DMyDlg.cpp --

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
    //{{AFX_MSG_MAP(CMyDialog)
    ON_MESSAGE(WM_KICKIDLE, OnKickIdle)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

LRESULT CMyDialog::OnKickIdle(WPARAM wParam, LPARAM lParam)
{
   UpdateDialogControls(this, FALSE);


   return (LRESULT)1;
}

반응형
반응형

COLLADA (I'm saying it with a "ah" at the end), and Assimp (ple as that).

And so, why COLLADA? Simple:

  • COLLADA is an open standard made by Khronos (Sony specifically). The beauty of an open standard format is that it's, well, a standard! You can be assured that any output of a standard-conformant product would also read correctly by another standard-conformant product. Sad to say though, some 3d modelling products aren't that particular in their measures for standards conformance for COLLADA. But still be rest assured: Blender, Maya, 3ds Max and all the other big names in 3d modelling has good support for the format.
  • COLLADA uses XML. This makes it much more simpler for you if your planning to create your own reader or writer.
  • ADDITIONAL: COLLADA is, I think, the only format that is not tied to a specific company. This is a very good thing for us, you know.
  • ADDITIONAL 2: It is known that COLLADA is slow to be parsed. That's true. But think of it: all other non-binary formats (like fbx) have also the same issues. For your needs, COLLADA should suffice.
  • ADDITIONAL 3: COLLADA supports animations!

For the importer library, I highly recommend Assimp. Why?

  • Assimp has support for any popular format you can imagine. It has a unified interface for all formats so that switching to another format is less of a pain.
  • Assimp is extensible. You can thus import your proprietary format and still not modify your code.
  • ADDITIONAL 4: Assimp is open source! Let's support open source software!


http://goo.gl/7VVqD

반응형
반응형

잘 안나오네 , 아시는분 주소좀 찍어주세요~



http://wrice.egloos.com/m/5419686


게임 출시는 두달 정도 남은것 같지만 실제 개발은 다다음주면 끝입니다.
막바지 작업으로 최적화 작업을 하는 중이지요...

그런 이유로 요즘 PS3 용 라이브러리인 Edge 를 살펴보고 있습니다.
PS3 는 Vertex Shader 가 XBox360 보다 별로 힘을 못씁니다.

반면에 SPU 가 Vertex Shader 의 일을 할수 있도록 설계되어있습니다.
그리고 이렇게 Vertex Shader 의 기능을 사용하도록 도와주는 라이브러리가 바로 Edge 입니다. Sony 에서 개발해서 소스랑 예제랑 문서를 모두 함께 제공하고 있습니다. (라고는 해도 일반인에게 공개되어있지는 않은듯 합니다.)

사실 SPU 로 프로그래밍 하는것이 동기화 문제 때문에 까다롭습니다. 그래서 별로 사용할 일이 없는데 Edge 라이브러리를 보면 상당히 깔끔하게 SPU 를 활용할수 있도록 잘 짜여져 있는것 같습니다.

지금 시점에서, 최신 버전은 1.2 버전인데, 1.1.1 에서 1.2 로 넘어오면서 MLAA 기능을 사용할수 있도록 하고 있어서 매우 흥미롭습니다. 이번 프로젝트에서는 무리이지만 다음번 프로젝트에서는 꼭 사용해볼 예정입니다.

Edge 라이브러리로 가능한것들 중에는 압축/해제 라든지, Skinning, Animation 등이 있습니다.

반응형
반응형


http://blog.naver.com/ultimidou/130095833416

http://blog.naver.com/PostView.nhn?blogId=kimgudtjr&logNo=140116


메모리 - 가상 메모리 할당 함수, VirtualAlloc, 예약, 확정, 보호속성, 대용량 메모리 할당

 
[ C 런타임 함수 ]

 

응용 프로그램에서 메모리가 필요할 경우 운영체제에게 메모리 할당을 요청한다. 운영체제는 원칙적으로

응용 프로그램의 메모리 할당 요청을 거절하지 않으며 한 번 할당한 메모리는 해제하기 전에는

다른 할당 요청에 사용되지 않는다. Win32에서 메모를 할당하는 바업에는 여러 가지가 있는데 가장

간단한 방법이 C 런타임 함수를 사용하는 것이다. 4G 평면 메모리 모델의 간단한 구조 덕분에

malloc, free 두 함수만 사용해도 기본적인 메모리 할당은 할 수 있다 원형은 다음과 같다.

 void *malloc(size_t size);
 void free(void *membolck);

malloc의 인수로 할당하고자 하는 메모리의 크기를 바이트 단위로 밝히기만 하면 된다. 운영체제는

물리적인 메모리를 할당하여 가상 주소 공간에 맵한 후 그 번지를 리턴한다. 이 때 리턴되는 값은

void 포인터 형이므로 반드시 원하는 타입으로 캐스팅해야 한다. 만약 메모리 부족으로 할당이 되지

않을 경우는 에러에 해당하는 NULL을 리턴한다. win16에서는 malloc의 리턴 값을 반드시 점검해 보아야

했으니나 Win32에서는 메모리 할당이 실패하는 경우가 극히 드물기 때문에 종종 리턴값 점검을 생략한다.

(그렇다고 해서 생략하는 것이 반드시 좋다는 뜻은 아니다.) malloc 으로 할당한 메모리를 다시 사용 후

free로 해제한다.

 

------------------------------------------------------------------------
메모리 할당 해제 예제 생략... (너무 쉬우므로..)
------------------------------------------------------------------------

 

참고로 잘 사용되지는 않지만 malloc와 유사한 다음과 같은 할당 함수들이 있따.

void *calloc(size_t num, size_t size);
void *realloc(void *memblock, size_t size);

calloc은 size크기의 변수값 num개분에 해당하는 메모리를 할당한다. malloc(size*num) 과 동일하되

다만 필요한 메모리 양을 좀더 논리적으로 나타낸다는 점만 다르다.  realloc은 이미 할당된 메모리의

크기를 변경하여 재할당하는 함수이다. 이미 할당한 메모리르 더 크게 할당하거나 더 작게 축소하고자 할 때

realloc 함수를 사용한다. 확장시는 연속된 공간에 재할당하기 위해 메모리의 위치가 변경될 수도 있다.

malloc, free 함수는 Win16 에서는 물론이고 그 이전의 도스 프로그래밍에서도 사용하던 아주 오래된 함수이다.

malloc은 절대 번지를 할당하기 때문에 (Win16 환경에서는 절대번지 할당) 운영체제가 메모리르 이동하거나

스왑할 수 없는 몇 가지 잠재적인 문제가 있어 Win16 환경에서는 잘 사용되지 않았다. 그러나

가상 주소 공간을 지원하는 Win32 환경에서는 다시 이 함수들이 사용되는데 Win32의 메모리는 원칙적으로

이동 가능(Moveable)하며 언제든 스왑(Descardable) 할 수 있기 때문이다.

운영체제가 필요에 의해 가상 메모리상의 위치를 옮기더라도 페이지 테이블을 같이 수정하면 응용 프로그램은

자신이 알고 있는 포인터로 계속 그 메모리를 사용할 수 있다. 가상 쉽고 또 무난하므로 특별한 기능 제한

(메모리 보호, 엑세스 지정 등) 없이 메모리 할당 자체가 목적이라면 이 함수만 사용해도 무방하다.

C++의 객체를 동적으로 할당할 때는 new연산자를 사용한다. new 연산자를 피연산자로 주어진  클래스 형

객체만큼의 메모리를 할당할 뿐만 아니라 해당 클래스의 생성자를 호출하여 객체를 초기화하기까지 한다.

그리고 해당 객체의 포인터를 리턴한다. 이렇게 동적으로 생성된 객체는 delete 연산자로 파괴하는데

다음이 간단한 사용 예이다.


 MyClass *pObj;
 pObj = new MyClass(1,2);
 // pObj를 사용한다.
 delete pObj;

하나의 객체뿐만 아니라 객체 배열을 할당할 수도 있다. 객체 위주로 프로그램을 작성할 때는 주로

이 연산자를 사용하여 메모리르 할당한다. C++ 언어가 제공하는 연산자이므로 자세한 문법에 대해서는

C++ 문법서를 참고하기 바란다.


================================================================================
[ 가상 메모리 할당함수 ]

 

응용 프로그램이 필요로 하는 메모리르 할당할 때는 앞에서  살펴본 malloc 함수 , new 연산자만 써도

충분하다. Win32에서 추가된 가상 메모리 할당 함수들은 전통적인 이런 함수들에 비해 몇 가지 추가적인

이점들을 제공하며 메모리에 대한 좀 더 섬세한 통제를 할 수 있다. 단순히 할당해서 사용할 목적이라면

malloc 함수를 쓰고 가상 메모리 구조의 이점을 활용하고 싶다면 가상 메모리 함수를 사용하면 된다.

가상 메모리 함수가 malloc 함수에 비해 가지는 이점은 다음 두 가지이다.


------------------------------------------------------------------------------------
○ 메모리를 예약 상태로 할당할 수 있다. 예약이란 물리적인 메모리를 소비하지 않으면서 주소 공간만을

미리 할당해 놓는 방법이다. 이렇게 예약된 페이지는 필요할 때 언제든지 필요한 부분만 확정해서

사용할 수 있으므로 realloc 회수를 줄일 수 있다.

○ 할당한 메모리의 엑세스 권한을 지정할 수 있다. malloc으로 할당한 메모리는 언제나 읽기/쓰기가

가능하지만 가상 메모리 함수로 할당한 메모리는 읽기 전욕, 액세스 금지 속성을 가질 수 있어

실수로 인한 데이터 파괴를 막을 수 있다.
------------------------------------------------------------------------------------

 

이 외에도 여러 가지 차이가 있지만 대부분이 이 두 가지 차이점으로 인해 파생되는 차이점이다.

가상 메모리 할당 함수는 일단 다음 두 가지가 있다. 할당 할때는 VirutalAlloc 함수를 사용하고

해제할 때는 VirtualFree 함수를 사용한다.


LPVOID VirtualAlloc(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect);

BOOL VirtualFree(LPVOID lpAddress, DWORD dwSize, DWORD dwFreeType);

첫 번째 인수 lpAddress는 할당하고자 하는 메모리의 절대 번지를 지정하되 NULL이면 시스템이 알아서

할당 번지를 지정한다. 동적으로 메모리를 할당할 때 할당 위치는 별 의미가 없으므로 보통 NULL을 주되

예약된 페이지를 확장할 때는 예약되어 있는 번지를 지정해야 한다. 두 번째 인수 dwSize는 할당하고자

하는 메모리의 양을 바이트 단위로 지정한다. 세 번째 인수 flAllocationType은

할당 방법을 지정한다.

 

------------------------------------------------------------------------------------
할당 방법  설명
------------------------------------------------------------------------------------
MEM_RESERVE 물리적인 메모리의 할당없이 주소 공간만을 예약한다.

MEM_COMMIT 물리적인 메모리를 확정한다.

MEM_TOPDOWN 가급적 높은 번지에 메모리를 할당한다. NT이상에서만 쓸 수 있다.
------------------------------------------------------------------------------------

 

네 번째 인수 flProtect는 할당한 페이지의 액세스 타입을 지정하며 보통 PAGE_READWRITE로 지정한다.

이에 대해서는 잠시 후에 자세하게 알아볼 것이다. 메모리 할당에 성공하면 할당된 메모리의 번지를

리턴하며 실패했을 경우 NULL을 리턴한다.


VirtualFree 함수는 할당된 페이지를 해제한다. 첫 번째 인수 lpAddress는 해제하고자 하는 메모리의

선두 번지를 지정하며 두 번째 인수 dwSize는 해제하고자 하는 메모리의 크기를 지정한다.

세 번째인수 dwFreeType은 다음 두 값중 하나이되 둘을 같이 쓸 수는 없으며 반드시 따로 사용해야 한다.

만약 확정된 메모리르 해제하려면 확장 해제 후 예약 해제해야 한다.


------------------------------------------------------------------------------------
값  설명
------------------------------------------------------------------------------------
MEM_DECOMMIT 확정된 페이지를 확정 해제한다.

MEM_RELEASE 예약된 페이지를 예약 해제한다.
------------------------------------------------------------------------------------

다음은 가상 메모리 할당 함수를 사용하는 간단한 예이다.

------------------------------------------------------------------------------------
ptr = (int*)VirtualAlloc(NULL, sizeof(int)*10, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

VirtualFree(ptr,sizeof(int)*10,MEM_DECOMMIT);
VirtualFree(ptr,0,MEM_RELEASE);

------------------------------------------------------------------------------------


================================================================================

[ 예약과 확정 ]

 

Win32 프로세스가 가지는 4G의 가상 주소공간은 "페이지"라는 단위로 구성된다.  한 페이지의 크기는

시스템 마다 다른데 가장 많이 사용되는 인텔 계열의 CPU에서는 4K 바이트의 크기를 가진다.

윈도우즈는 페이지 단위로 주소 공간을 관리한다.  즉 할당하거나 해제하는 단위가 페이지 단위라는

뜻이다. 주소 공간을 구성하는 각 페이지는 다음 세 가지 상태 중 하나의 상태로 존재한다.


------------------------------------------------------------------------------------
상태  설명
------------------------------------------------------------------------------------
자유 영역(Free)  - 사용되지 않는 자유 영역이다. 언제든지 예약하거나 확정할 수 있다.

예약(Reserved)  - 장래 사용을 위해 예약만 되어 있는 페이지이며 물리적인 메모리가 할당되어 있지 않다.
  주소 공간만 할당되어 있는 상태이다.

확정(Committed) - 가상 메모리와 연결되어 있는 상태이며 바로 사용할 수 있다. 물리적 메모리를 소모한다.
------------------------------------------------------------------------------------

 

프로세스가 처음 실행되었을 때 부부분의 주소 공간은 자유 영역일 것이며 실행 파일의 이미지와 공유 DLL등이

확정되어 사용될 것이다. 자유 영역으로 남아있는 주소 공간은 언제든지 할당해 사용할 수 있는데

할당의 수준이 예약과 확정 두 종유가 있다. 예약이란 말 그대로 주소 공간만 할당하여 이 번지가

다른 목적으로 사용되지 않도록 하는 것이며 확정은 물리적인 메모리가 실제로 필요할 때에

RAM 또는 페이징 파일을 주소 공간에 연결(MAP)하는  것이다.

 Win16에는 없던 이런 예약과 확정이라는 것이 왜 필요하게 되었는가 하면 물리적인 메모리와

논리적인 주소공간이 분리되었기 때문이다. 논리적인 주소 공간을 할당하는 것이 예약이고 에약된 주소

공간에 물리적인 메모리르 연결하는 것이 확정이다. 주소 공간만을 할당하는 예약은 물리적인 메모리를

전혀 소모하지 않는다. 그래서 충분한 주소 공간을 미리 예약해 두어도 전혀 손해를 볼 것이 없다.

일단 예약된 주소 공간은 다른 할당 요청에 의해 다시 할당되지 않으므로 필요할 때마다 물리적인

메모리를 확정해서 사용하면 된다.

예를 들어 어떤 프로그램에서 10M바이트의 연속적인 메모리가 필요하다고 하자 그런데 당장은 이 메모리가

한꺼번에 사용되지 않지만 반드시 연속적인 메모리여야 한다면 일단 10M의 주소 공간을 예약해 둔다.

예약만 했으므로주소 공간만 할당되었을 뿐 물리적인 메모리는 전혀 소모하지 않았다. 그리고 필요할 때마다

원하는 위치의 주소 공간을 확정하여 물리적 메모리와 연결하여 사용하면 된다. 주소 공간이 연속되어

있으므로 예약된 주소와 연결되는 물리의 번지가 반드시 연속되지 않아도 아무 문제가 없다.

메모리를 예약할 것인가 확정할 것인가는 VirtualAlloc 함수의 세 번째 인수 flAllocationType으로

지정하는데 예약만 할 때는 MEM_RESERVE를 주고 예약된 메모리를 확정할 때는 MEM_COMMIT를 준다.

예약과 동시에 확정하려면 두 플래그를 OR로 묶어서 같이 지정한다. 예약과 확정을 따로 하고 싶다면

다음과 같이 두 번 호출한다.

ptr = (int*)VirtualAlloc(NULL,sizeof(int)*10,MEM_RESERVE,PAGE_READWRITE);
ptr = (int*)VirutalAlloc(NULL,sizeof(int)*10,MEM_COMMIT,PAGE_READWRITE);

예약에 의해 주소 공간이 임의의 번지에 먼저 할당되고 확정에 의해 이 주소 공간이 가상 메모리에

맵된다. 예약만 하고 확정은 하지 않은 상태는 주소 공간만 할당되어 있고 물리적인 메모리와 맵되어

있지 않은 상태이기 때문에 실제 메모리 구실을 할수 없다. 따라서 다음과 같은 코드는 AccessViolation

예외를 발생시킨다.

ptr = (int*)VirtualAlloc(NULL,sizeof(int)*10,MEM_RESERVE,PAGE_READWRITE);

ptr[0] = 'S';

메모리를 예약만 했는데 이 때 예약된 번지수가 리턴되기는 하지만 이 번지는 가상 주소 공간의

한 지점일 뿐 실제 물리적인 메모리와 연결되지 않았다. 그러므로이 번지에 무엇인가 값을 대입하는 것은

불법이며 읽기만 해도 불법이다.


================================================================================

[ 할당 단위와 페이지 ]

 

VirtualAlloc 함수가 메모리를 할당할 때는 바이트 단위를 사용하지 않는다. 4G나 되는 주소공간을

바이트 단위로 사용하는 것은 너무 비효율적이기 때문에 일정한 단위로 주소 공간을 분할한다. 마치

하드딧크가 바이트 단위로 파일을 기록하지 않고 섹터, 클러스터 단위를 사용하는 것처럼 말이다.

클러스터 단위로 파일을 기록하면 낭비되는 디스크 공간이 생기지만 속도는 훨씬 더 빨라진다.

가상 주소 공간의 단위는 두 가지가 있다. 우선 할당의 시작점을 지정하는 할당 단위(Allocation Granualrity)가

있고 할당의 크기를 지정하는 페이지(Page)가 있다. 이런 단위를 사용하여 메모리를 관리하는 이유는

메모리가 지나치게 조각나는 것을 방지하고 좀 더 신속하게 메모리를 관리하기 위해서이다. 물론 바이트

단위로 메모리를 관리하는 것이 효율 면에서는 이상적이지만 이렇게 하면 페이지 테이블이 지나치게

커질 것이며 운영체제는 너무 너무 바빠질 것이다.

VirtualAlloc으로 메모리를 할당(예약하거나 확정)할 때 그 시작점은 반드시 할당 단위의 경계선에

정렬된다. 즉 할당 단위의 배수 위치에서 할당이 시작된다. 대부분의 플랫폼에서 할당 단위는 64K이므로

가상 메모리 공간은 64K 단위로 할당된다고 할 수 있다.  예를 들어 다음과 같이 예약 명령을

내렸다고 하자.

ptr = (int*)VirtualAlloc(0x71234, sizeof(int)*10, MEM_RESERVE, PAGE_READWRITE);

예약의 시작점을 0x71234번지로 강제로 지정하였다. 그러나 운영체제는 정확하게 이 번지에서 할당을

시작하지 않고 할당 단위의 배수가 되도록 번지를 내림하여 할당한다. 이 경우 실제 예약되는 번지는

0x70000번지가 된다. 하위 2바이트를 0으로 만든 번지에서 할당된다고 생각하면 된다.

또 할당된 영역의 크기는 반드시 페이지 단위의 배수가 된다. 페이지의 크기는 플랫폼에 따라서 다른데

인텔을 비록한 대부분의 시스템에서 페이지 크기는 4K바이트이다. 예를 들어 10K의 크기만큼 할당을

요청했다면 실제로 할당되는 영역의 크기는 12K가 될 것이다. 현재 플랫폼에서 할당 단위와 페이지 크기를

조사하고 싶으면 GetSystemInfo 함수를 사용하면 된다. 다음은 이 함수를 사용하여 할당 단위와 페이지

크기를 조사하는 간단한 예제이다.

<GetSystemInfo 함수사용 예> (독자는 콘솔어플리케이션으로 했음..)


---------------------------------------------------------

#include <stdio.h>
#include <windows.h>

int main()
{

 SYSTEM_INFO si = {0};
 
 GetSystemInfo(&si);

 printf("Page Size : %d\n",si.dwPageSize);
 printf("Min Addr : %d\n",(int)si.lpMinimumApplicationAddress);
 printf("Max Addr : %d\n",(int)si.lpMaximumApplicationAddress);
 printf("Alloc Gra : %d\n",si.dwAllocationGranularity);
 

 return 0;
}
---------------------------------------------------------


할당 단위는 Wion32가 실행되는 현재까지의 모든 플랫폼에서 64K이며 페이지 크기는 Alpha 시스템만

8K이고 그 외의 CPU(Intel, MIPs, PowerPC)에서는 모두 4K이다.  모든 플랫폼에서 이상없이 돌아가는

프로그램을 만들려면 GetSystemInfo 함수로 이 값들을 잘 조사해 보아야 하나 내부적인 메모리 관리에만

사용되므로 응용 프로그램 수준에서 실제로 이 정보가 유용한 경우는 별로 없다.

 

================================================================================

[ 보호 속성 ]

 

VirtualAlloc의 네 번째 인수 flProtect는 할당하고자 하는 메모리의 액세스 타입(Access Protection)을

지정한다. Win32 가상 메모리의 특징 중 하나가 메모리 페이지마다 액세스 타입을 설정하여 미연의

실수를 방지할 수 있는 점이다. 마치 파일에 읽기 전용 속성을 주어 실수로 지워지지 않도록 하는 것과

개념적으로 동일하다 지정 가능한 플래그는 다음과 같다.   이 중 PAGE_GUARD, PAGE_NOCACHE 플래그는

PAGE_NOACCESS 플래그를 제와한 다른 플래그와 함께 사용할 수도 있다.


< AirtualAlloc의 네 번째 인자에 줄 수 있는 옵션 값 >
---------------------------------------------------------------------
액세스 권한  설명
---------------------------------------------------------------------
PAGE_READONLY  읽기만 가능하다. 이 메모리는 쓰기를 할 수 없다.
PAGE_READWRITE  읽기 쓰기 가능하다.
PAGE_EXECUTE  실행만 가능하다. 읽기, 쓰기 모두 할 수 없다.
PAGE_EXECUTE_READ 실행, 읽기, 쓰기를 가능하다.
PAGE_GUARD  보호 페이지로 지정한다. 이 페이지에 읽기 , 쓰기를 시도하면
   STATUS_GUARD_PAGE 예외가 발생하며 보호 페이지 상태가 해제
   된다. 보호 페이지는 메모리의 끝을 표시하는 용도로 주로 사용된다.
   NT 이상만 지원한다.
PAGE_NOACCESS  어떤 액세스도 하지 못하게 한다. 읽기, 쓰기 , 실행 어떤 것도 하지 못하게 한다.
PAGE_NOCACHE  캐시를 금지시킨다. 일반적으로 응용 프로그램은 이 플래그를 사용하지 않는 
   것이 좋다. 디바이스 드라이버 등의 시스템 소프으웨어에서 이 플래그를
   사용한다.
PAGE_EXECUTE_WRITECOPY 공유된 영역에 쓰기를 할 때 사본을 작성한다. NT이상만 지원한다. 
---------------------------------------------------------------------


일반적인 용도로 읽기도 하고 쓰기도 할 메모리라면 PAGE_READWRITE 로 지정하여 마음대로 읽고 쓰도록

하면 된다. 그러나 특정 목적으로 읽기만 하고 쓰지는 못하게 하려면 PAGE_READONLY 플래그를 지정한다.

이렇게 할당된 메모리는 읽을 수는 있어도 쓸 수는 없다. 만약 읽기 전용의 메모리에 쓰기를 시도하면

Access Violation 예외가 발생한다


ex) 
ptr = (int*) VirtualAlloc(NULL,sizeof(int)*10, MEM_RESERVE | MEM_COMMIT, PAGE_READONLY);

int i = ptr[0];  // 읽기 가능
ptr[0] = 'x'; //쓰기 불가능

읽기 전용, 쓰기 전용의 말은 다 이해하겠는데 실행 전용 이라는 말은 선뜻 이해가 되지 않을 것이다.

읽기는 해당 메모리의 데이터를 읽을 수 있다는 말이며 실행은 해당 메모리의 코드를 CPU가

실행할 수 있다는 뜻이다. 현재까지의 모든 시스템(인텔,알파)은 읽을 수 있으면 실행도 가능하므로

사실 아직까지 읽기 전용은 같은 뜻이다. Win32가 플랫폼에 독립적인 API 이다 보니 미래에 읽기와

실행을 구분하는 CPU를 위해 이런 액세스 타입을 미리 준비해두고 있을 분이다. 메모리의

엑세스 타입은 할당할 때 지정하지만 실행중에도 다음 함수를 사용하여 변경할 수 있다.

하지만 응용 프로그램 수준에서 메모리의 액세스 타입을 그거솓 실행중에 변경하는 경우는 지극히 드물며

예를 들기도 무척 곤란하므로 이런 함수도 있다는 것만 알아두자. 꼭 예를 든다면 아주 중요하나 데이터를

특정 함수만 변경하고 싶을 때 읽기 전요응로 만들어 두고 이 함수에서만 액세스 타입을 잠시  바꾸는

정도가 있다. 시스템의 함수를 훅킹하는 고난이도의 기법을 구사할 때 이 함수를 슨다.

가상 메모리의 보호 속성은 프로그램 로더가 사용한다. 응용 프로그램을 메모리로 읽어올 때 실행파일(PE)에

기록되어 있는 섹션 속성에 따라 쓰기가 가능한 메모리 영역과 읽을 수만 있는 메로리 영역이 구분되어

가상 메모리에 배치된다. 일반적으로 코드영역은 읽기 전용이며 번역변수 영역은 읽고 쓸 수 있는

영역이다. 하지만 문자열 상수는 읽기 전용 영역에 배치되므로 이 값은 실행중에 변경할 수 없다.


다음 예제를 보자

------------------------------------------------------------------
#include <stdio.h>


char *str = "string";
int i = 0;

int main()
{
 
 str[0] = 'A'; // 메모리 액세스 에러

 i = 10;  // 메모리 액세스 성공

 

 return 0;
}
------------------------------------------------------------------

 

위에서 str[0] = 'A'는 에러가 날것이고 i = 10은 에러가 나지 않을 것이다.

이것이 문자열 상수 영역과 정 전역변수 영역의 메모리 접근 권한의차이 이다.


16비트의 메모리는 이런 구분이 없기 때문에 우발적인 사고로 코드 영역을 건드릴 수도 있었는데

32비트의 가상 메모리는 메모리에 속성을 부여함으로써 변경되지 말아야 할 영역을 보호 할 수 있다.


PAGE_GUARD 속성은 가드 페이지를 설정함으로써 효율적인 스택 확장에 사용된다.

스택은 기본적으로 1M 예약되며 그 중 한 페이지 분량이 4K 정도만 확정된 채로 생성된다.

예약된 1M는 스택의 최대 크기이며  확정된 페이지는 당장 사용할 수 있는 영역인데 스택을 많이

사용하면 확정을 점점 늘린다. 이때 스택을 언제 확장할지를 결정하기 위해 운영체제가 사용하는

속성이 PAGE_GUARD이다. 스택이 확장되는 과정은 아래와 같다.


 ---------------------------------
 예약| 예약 | 예약 | 가드 | 확정   ( 확장 전)
 ---------------------------------
 낮은번지   높은번지

 ---------------------------------
 예약| 예약 | 가드| 확정 | 확정   ( 확장 후)
 ---------------------------------
 낮은번지   높은번지

 격자 하나가 1페이지 이다.


최초 제일 높은 번지의 한 페이지만 확정되어 있으며 이 안에서 함수를 호출하고 지역 변수를 생성한다.

그러다가 스택 사용량이 늘어 가드 페이지에 닿으면 예외가 발생하는데 운영체제는 이 예외가 발생했을 때

가드 페이지를 추가로 확정하고 바로 다음의 예약 페이지를 다시 가드 페이지로 설정한다.

만약 가드 페이지가 없다면 스택을 액세스할 때마다 확정 여부를 점검해야 하므로 무척 비효율적일 것이다.


이런 식으로 스택은 점차적으로 확장되는데 단, 마지막 페이지를 확정하지 않으므로써 예약된 1M 영역을

절대로 넘지는 않는다. 만약 스택 크기다 !M를 넘어서 오버플로우가 발생했다면 이는 대개의 경우

프로그램의 논리가 잘못된 것이다. 스택은 함수를 호출함에 따라 오르락 내리락거리는 것인데

이 정도로 커졌다면 재귀 호출이 잘못된 경우이므로 예외를 일으키고 죽도록 내버려 두는 편이 더 낫다.

참고로 95/98 에서는 PAGE_GUARD 속성이 지원되지 않기 대문에 PAGE_NOACCESS 속성이 대신 사용된다.


================================================================================

[ 메모리 잠금 ]

 

가상 주소 공간은 논리적으로 존재할 뿐이며 데이터나 코드가 저장되는 곳은 가상 메모리 이다.

여기서 가상 메모리라고 칭하는 것은 RAM과 하드 디스크의 페이징 파일을 합쳐 부르는 말이다.

페이징 파일도 RAM보다 좀 느릴 뿐이지 분명히 메모리이다. 운영체제는 RAM과 페이징 파일 사이를

끊임없이 교체하면서 돌아간다. 당장 필요한 부분은 RAM으로 읽혀지며 당분간 사용되지 않을 부분은

페이징 파일로 이동된다.

운영체제의 이런 가상 메모리 관리는 응용 프록램 입장에서 볼 때 완전히 투명하다. 즉 원하는 데이터가

RAM에만 있도록 할 수 있다. 즉 페이징 파일로 복사하지 못하게 금지할 수 있는데 이렇게 하면 원하는 데이터를

물리 RAM에서 바로 찾을 수 있으므로 속도가 더 발라진다. 이 때는 다음 두 함수를 사용한다.


BOOL VirtualLock(LPVOID lpAddress, DWORD dwSize);
BOOL VirtualUnlock(LPVOID lpAddress, DWORD dwSize);

VirtualLock 함수는 lpAddress가 지정한 번지로부터 dwSize 길이 만큼의 메모리 페이지를 잠근다.

이렇게 되면 운영체제는 이 번지의 데이터는 페이징 파일로 보내지 않고 항상 RAM에 남아 있도록 하여

최대한 신속하게 사용할 수 있도록 보장한다. 이때 lpAddress 번지는 반드시 가상 메모리가 맵되어 있는

확정 상태여야만 한다. 그렇지 않으면 잠금 동작 자체가 무의미하다. 장금을 풀 때는 VirtualUnlock 함수를

사용한다.

잠겨진 메모리에 대해서는 페이징 파일로 스왑하지 않아 원하는 데이터가 RAM에 없는 상태(Page Fault) 가

발생하지 않는다. 단 예외적으로 해당 프로세스가 액티브 상태가 아니면 이 때는 잠간 페이지라도

페이징 파일로 이동시켜버릴 수 있다. 메모리를 잠그면 응용 프로그램은 자신이 필요로 하느 데이터를 언제나

RAM에서 읽으므로 더 빨리 실행될 수 있어서 좋겠지만 이 기능은 반드시 꼭 필요한 부분에만 신중하게

사용해야 한다. 그렇지 않고 남발하게 되면 운영체제의 시스템 관리 능력을 저해하여 자칫하면 전반적으로

속도가 느려질 수 있다.

Win32의 메모리 관리 알고리즘은 상당히 정교하며 효율적으로 작서오디어 있으므로 굳이 메모리를

잠그지 않아도 큰 불편 없이 쓸 수 있다. 메모리 잠금을 반드시 사용해야 하는 프로그램은 디바이스 드라이버

정도이다. 응용 프로그램 수준에서는 거의 쓸 일이 없으며 함부로 메모리 관리에 개입해서는 안된다.

멀티 태스킹은 운영체제의 지휘 아래응용 프로그램들의 자발적인 협조에 의해 부드럽게 돌아가는 것인데

특별히 이유없이 혼자서 자원과 시간을 독점하는 것은 금물이다.


================================================================================

[ 대용량 메모리 ]


가상 메모리를 제대로 사용하는 예제를 만들어 보자. 만약 어떤 프로그램이 실행중에 데이터를 읽어들이는데

다 읽기 전에는 정확한 용량을 알 수 없으며 최대 100M까지의 용량이 필요하다고 해 보자.

이 경우 필요한 최대값인 100M을 몽땅 할당해 놓고 작업을 시작한다면 시스템의 메모리 실장량에 따라

메모리 할당이 실패할 수도 있다. 실제 필요한 용량은 그보다 훨씬 작은데 그렇다고 해서

최대값을 무시할 수도없고, 이럴 때 바로 가상 메모리의 예약과 확정 기능을 사용한다. 다음 예제는

그 예를 보여 부는데 작업 관리자를 열어 놓고 메모리의 변화를 잘 관찰해 보아라.

 

<가상 메모리 할당함수 사용>
------------------------------------------------------------------------------------

#include <windows.h>
#include <windows.h>

#define MEGA 1048576
PBYTE stptr = NULL;
TCHAR Status[256] = TEXT("할당되지 않았습니다.");


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("First");  //윈도우 이름 및 타이틀바에 등록할 문자열

void FreeRecords();
void ReadRecords();

void Error(const char *mes);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 
 g_hInst = hInstance;

 //------------ 아래 부분은 윈도우 클래스를 설정해주는 것이다. --------------------

 WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
 WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
 WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance = hInstance;
 WndClass.lpfnWndProc = WndProc;
 WndClass.lpszClassName = lpszClass;
 WndClass.lpszMenuName = NULL;
 WndClass.style = CS_HREDRAW | CS_VREDRAW;

 //------------ 위 부분은 윈도우 클래스를 설정해주는 것이다. --------------------

 RegisterClass(&WndClass);   //  <-- 여기서는 위에서 설정한 클래스를 등록한다.

 hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
      CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);   // 설정하고 등록한 윈도우를 생성한다.

 ShowWindow(hWnd,nCmdShow);   //생성한 윈도우를 출력..(이 함수를 호출하지않으면 윈도우가 보이지 않는다.)

 while(GetMessage(&Message,NULL,0,0))   //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
 {
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }

  return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
 HDC hdc;
 PAINTSTRUCT ps;
 TCHAR *Mes = TEXT("왼쪽 마우스 버튼 : 메모리 할당, 오른쪽 마우스 버튼:메모리 해제");

 switch(iMessage)
 { 
 case WM_CREATE:
  hWndMain = hWnd;
 srand(GetTickCount());
  return 0;

 case WM_LBUTTONDOWN:
  SetCursor(LoadCursor(NULL,IDC_WAIT));
 ReadRecords();
 SetCursor(LoadCursor(NULL,IDC_ARROW));
  return 0;

 case WM_RBUTTONDOWN:
  FreeRecords();
  return 0;

 case WM_PAINT:
  hdc = BeginPaint(hWnd,&ps);
  TextOut(hdc,50,50,Mes,lstrlen(Mes));
  TextOut(hdc,50,80,Status,lstrlen(Status));
  EndPaint(hWnd,&ps);
  return 0;

 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }

 return DefWindowProc(hWnd,iMessage,wParam,lParam);  //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}


void FreeRecords()
{
 if(stptr != NULL)
 {
  if(VirtualFree(stptr,(100 * MEGA),MEM_DECOMMIT) == 0)
    Error("메모리 확정 해제 실패");

  if(VirtualFree(stptr,0,MEM_RELEASE) == 0)
    Error("메모리 예약 해제 실패");

  stptr = NULL;
 }

 wsprintf(Status,TEXT("할당되지 않았습니다."));
 InvalidateRect(hWndMain,NULL,TRUE);
}

void ReadRecords()
{
 int c = 0;
 int RecSize = 0;

 PBYTE nowptr, endptr;

 FreeRecords();

 stptr = (PBYTE)VirtualAlloc(NULL,(100 * MEGA),MEM_RESERVE,PAGE_READWRITE);

 if(stptr == NULL) Error("메모리 예약 실패");

 nowptr = stptr;
 endptr = stptr;

 c = rand() % 90 + 10;

 for(int i=0; i<c; i++)
 {
  if( (endptr - nowptr) < MEGA )
  {
   VirtualAlloc(endptr,MEGA,MEM_COMMIT,PAGE_READWRITE);
   endptr += MEGA;
  }

  RecSize = ((rand() % 100)+1)*10240;
  memset(nowptr,i,RecSize);
  nowptr += RecSize;
  
 }

 wsprintf(Status,TEXT("예약:100 메가, 확정:%d 메가, 사용%d 메가"),(endptr-stptr)/MEGA,(nowptr-stptr)/MEGA);
 InvalidateRect(hWndMain,NULL,TRUE);
}

void Error(const char *mes)
{
 MessageBoxA(0,mes,"error",0);
 exit(0);
}
------------------------------------------------------------------------------------


ReadRecords 함수에서 네트워크 또는 DB에서 레코드를 메모리로 읽어들이는데 레코드의 개수는 정해져

있지 않지만 최대 100까지 읽을 수도 있다. 또한 레코드 크기도 실제로 읽어봐야 알 수 있는데

작게는 10K 정도 되고 큰 레코드는 1M 정도 된다. 이 경우 필요한 메모리는 레코드 개수와 크기에 따라

100K~100M에 달하는데 문제는 실시간으로 읽어들이는 레코드이기 때문에 필요한 메모리 용량을

정확하게 알 수 없다는 것이다. 미래의 일을 예측할 수 없는 이런 상황이 항상 문제가 되는데

생각보다 자주 발생한다.

그렇다고 해서 최대 용량인 100M를 다 할당하는 것은 무리고 대충 충분한 용량인 50M 정도를 할당하는 것도

꺼림직하다. 이럴 경우 100M의 주소 공간을 예약만 해 놓고 필요할 때 그때 그때 메모리를 확장해서

사용하면 된다. ReadRecords 함수에서 stptr에 100M의 주소 공간을 예약하는데 예약만 했기 때문에

실제 메모리를 소모하는 것은 아니다. 그리고 루프를 돌면서 필요한 레코드들이 이 메모리로 읽어들이되

남은 메모리가 1M 미만이면 추가로 1M을 확장해서 사용한다. 이때 추가 확정되는 메모리가 반드시

기존의 영역과 연속적일 필요는 없는데 어차피 주소 공간에서는 연속적인 메모리로 인식되기 때문이다.

예제의 enptr은 할당된 메모리의 끝이며 nowptr은 읽어들인 레코드의 끝이다.  endptr에서 nowptr을

뺀 용량, 즉 현재 남은 용량이 다음 읽을 레코드의 최대 크기인 1M보다 작을 때 1M을 더 확정하여

endptr을 1M 더 뒤쪽으로 이동시킨다. endptr과 nowptr의 간격이 항상 1M 이상이 되도록 유지하는 것이다.

이런 식으로 메모리를 예약, 확정하면 실시간으로 필요한 연속적 메모리르 시스템에 무리를 주지 않고

할당해 사용할 수 있다. FeeRecords에서는 예약 및 확정된 메모리를 해제한다.

실행주으이 모습은 다음과 같다. (생략)

예약된 메모리 용량과 확정된 메모리 용량을 보여준다. 필요한 메모리 용량으 정확하게 계산하기

힘들 때는 이 방법대로 메모리를 할당해서 사용하면 된다. 다음은 똑같은 문제를 malloc, realloc 함수로

다시 작성해 본것이다. 동일한 동작을 하며 필요할 때마다 메모리를 재할당한다.

<C 메모리할당 함수 사용>


------------------------------------------------------------------------------------
#define MEGA 1048576
PBYTE stptr = NULL;

void FreeRecords()
{
 if(stptr != NULL)
 {
  free(stptr);
  stptr = NULL;
 }

 wsprintf(Status,"할당되지 않았습니다.");
 InvalidateRect(hWndMain,NULL,TRUE);
}

void ReadRecords()
{
 int i, c;
 int RecSize;
 int AllocSize;
 int RemainSize;
 
 FreeRecords();
 
 AllocSize = RemainSize = 2*MEGA;
 stptr = (PBYTE)malloc(AllocSize);

 if(stptr == NULL) Error("메모리 할당 실패");


 c = rand() % 91 + 10;

 for(i=0; i<c; i++)
 {
  if(RemainSize < MEGA)
  {
   AllocSize += MEGA;
   RemainSize += MEGA;
   stptr = (PBYTE)remalloc(stptr,AllocSize);
  }

  RecSize = ((rand() % 1000)+1)*10240;
  memset(arpre+AllocSize-RemainSize,i,RecSize);
  RemainSize -= RecSize;
 }

 wsprintf(Status,"총 할당량:%d 멕, 사용: %d 메가",
  AllocSize/MEGA,(AllocSize-RemainSize)/MEGA);

 InvalidateRect(hWndMain,NULL,TRUE);
}

------------------------------------------------------------------------------------


똑같은 동작을 하기는 하지만 realloc 함수가 굉장히 느리기 때문에 전체적으로 속도가 느리다는 큰

차이점이 있고 재할당할 때마다 번지가 바뀔 수 있다는 단점이 있다. 속도를 좀 높이려면 재할당할때

여유분을 충분히 주는 방법을 사용할 수는 있지만 가상 메모리를 쓰는 것보다는 확실히 성능이 떨어진다.

대용량의 가변적인 메모리를 다룰 때는 가상 메모리의 이점을 활용하는 것이 더 좋다.

가상 메모리는 예약 후 필요한만큼만 점진적으로 확정해 가며 쓸 수 있으므로 물리적인 메모리를

낭비하지 않으면서도 한번 예약한 번지가 바뀌지도 않아 쓰기 편리하고 속도도 빠르다.

단. 가상 메모리는 할당단위가 크므로 필요 메모리량이 클 때만 사용하는 것이 좋다. 연결 리스트의 노드처럼

작은메모리를 할당할 때는 realloc을 쓰는 방법이 더 바람직하다.

 

475366

반응형
반응형

BLOG main image


사용 예



calculate/check CRC32, MD5, SHA1, GOST, TTH, BTIH or other hash sums. 등이 포함되어있다





//Calculating SHA1 hash of a string

//const char* msg = "message digest";

const char* msg = "message digest";

unsigned char digest[64]={'\0',};

char output[130];



int res = rhash_msg(RHASH_CRC32, msg, strlen(msg), digest);

if(res < 0) {

fprintf(stderr, "hash calculation error\n");

return 1;

}


/* convert binary digest to hexadecimal string */

rhash_print_bytes(output, digest, rhash_get_digest_size(RHASH_SHA1), (RHPR_HEX | RHPR_UPPERCASE));

std::string dd= std::string(output,output+4);

//unsigned int data=  std::string(output,output+4);

printf("%s (\"%s\") = %s\n", rhash_get_name(RHASH_SHA1), msg, output);


}







http://rhash.anz.ru/


라이센스는 MIT 라이센스




Home    Download    Change Log    Manual    Hash Functions    Wiki    License ru | en 

RHash Program


RHash (Recursive Hasher) is a console utility for computing and verifying hash sums of files. It supports CRC32, MD4, MD5, SHA1, SHA256, SHA512, Tiger, DC++ TTH, BitTorrent BTIH, ED2K, AICH, GOST R 34.11-94, RIPEMD-160, HAS-160, EDON-R 256/512, Whirlpool and Snefru-128/256 algorithms. Hash sums are used to ensure and verify integrity of large volumes of data for a long-term storing or transferring.

Features:

  • Can calculate Magnet links.
  • Output in a predefined (SFV, BSD-like) or user defined format.
  • Ability to process directories recursively.
  • Updating of existing hash files (adding sums of files missing in the hash file).
  • Calculates several hash sums in one pass.
  • Portability: the program works the same under Linux, *BSD, or Windows.

RHash is written in pure C, small in size and is distributed under Open Source License.

Support This ProjectDownload RHash.

반응형
반응형

http://www.bcgsoft.com/FeatureTour/bcgcontrolbar-tour.htm



BCGSoft > Products > Product feature tour

Product feature tour

The feature is fully implemented
The feature is partially implemented
ProductBCGControlBar Pro (MFC)BCGSuite (MFC)BCGControlBar (Microsoft .NET)
General Application Look
Microsoft Office 2013 Look
Microsoft Office 2010 Look
Microsoft Office 2007 Look
Microsoft VS 2012 Look
Microsoft VS 2010 Look
Microsoft VS 2008 Look
Microsoft Office 2000/XP/2003 Look
Microsoft VS 6.0, VS.NET and VS 2005/2008 Look
Microsoft Internet Explorer Look
Microsoft Windows Themes Support
Carbon Look
Custom Application Look
Microsoft Office 2007/2010/2013 and Windows 7-style Ribbon Control
General Ribbon Features
Ribbon Designer
Ribbon Vista Aero Integration
Windows 7-like ("Scenic") Ribbon
Office 2010/2013-style Ribbon
Ribbon Panels
Ribbon Contextual Categories (Tabs)
Ribbon Elements
Ribbon KeyTips
Ribbon Palettes (Galleries)
Ribbon Customization
Ribbon Launch Button
Ribbon Main (Application) Button ("Perl")
Ribbon Backstage View
Ribbon Command Search
Ribbon Mini Toolbar ("Floaty")
Ribbon Status Bar
Ribbon Dialog Bar
Microsoft Office Style Toolbars
Microsoft Office XP/2000/2003/2007 look
Toolbar Editor
High and True color images support
"Pager" button (chevron)
Large icons support
Auto-build keyboard shortcut names in menus and ToolTips
Toolbar images
Toolbar images color transformation
"Locked" toolbars
Toolbar Menu buttons
Toolbar edit box buttons with spin button control and calculator
Toolbar combo box buttons
Toolbar font combo box and font size combo box buttons
Date/Time control for Toolbar
Built-in color picker
Built-in roll-up buttons (similar to CorelDraw)
Tabbed Toolbars
Explorer-style Toolbar
Microsoft Office Style Menus
Docking Microsoft Office-style menu bars with images
Microsoft Office 2000/XP/2003 menus (with recently used menu items)
Menu animations and shadows
Menu Tooltips
"Owner-draw" menu images
Left-side owner-draw logo
Most recently used (MRU) files and Windows list support
Microsoft Office-like "tear-off" ("detachable") menus
Right-alignment support for popup menus
Advanced Control Bars (Panes)
Shortcuts (Microsoft Outlook style) bar
Visual Studio 2005/2008/2010-style docking
Visual Studio style Docking/Resizable Control Bar
Microsoft Office-Style Task Pane
Visual Studio style Tabbed Control Bar
Visual Studio style Detachable Tabs
Visual Studio style Auto Hide Control Bars
Visual Studio style Toolbox
Advanced Dialog Bars
Application Bar
Enhanced Status Bar
Microsoft Office-style caption bar
Persistent rebars
Roll-up control bar
Microsoft Office style Print Preview
Advanced Document Management
MDI Tab Control
MDI Tab Groups
Persistent MDI State
Tabbed Views
OLE Document Support
Customization
Customizable toolbars and menus
Creation of user-defined toolbars at runtime
Context menu customization
Mouse event customization
Keyboard customization
Workspace manager
User defined tools
Alternative customization ("Alt+drag")
Quick customization
User-defined image editing (simple bitmap editor is included!)
Visualization and skins
Visualization and Skins
Visualization manager
Planner Control (Calendar)
Microsoft Outlook style Calendar
Day View
Work Week View
Week View
Month View
Single Appoinment
Recurring Events
Multi-Resource Support
Multi-Day and All Day Events
Integration with Calendar Control
Printing support
Chart Control
General Chart Features
Line Chart
Area Chart
Column and Bar Charts
Surface Chart
Pie, Doughnut and Torus Charts
Point Chart
Bubble Chart
Stock Chart
Histogram Chart
Long Data Line Chart
Historical Line Chart
Pyramid Chart
Funnel Chart
Radar Chart
Polar Chart
Ternary Chart
Chart Axis
Chart Series
Chart Virtual Series
Chart Data Markers
Chart Data Labels
Chart Legend
Chart Zoom and Scroll
Chart Objects
Chart and Plot Area
Chart Trendline Support
Chart Transitions Support
Chart Visualization Features
Chart Interoperability with other Library Components
Grid and Report Controls
General Grid Features
Grid Cell Types
Grid Virtual Mode
Grid Field Chooser
Grid Grouping Support
Grid Filter Support
Grid Filter Bar
Grid Merged Cells Support
Grid Data Binding
Grid Color Themes
Grid Frozen Columns
Grid Find Dialog
Hierarchical Grids
Report Control
Advanced Edit Control with IntelliSense and Syntax Highlighting
General Edit Control Features
Syntax Highlighting support
XML Schemas for Language Definition
Support for collapsible nodes (outlining)
Context-sensitive Tooltips
IntelliSense support
Line numbering
Markers and Color Blocks
Hyperlinks support
Symbol support
Undo/Redo support
Find and Replace
Export to HTML and RTF
MFC Document/View support
Gantt Control
General Gantt Control Features
Task types
Built-in resource grid
Task connectors
Collapsible groups (Grouped items)
Fully customizable appearance
Zoom In / Zoom Out
Gauges
Gauges Overview
Visual Designer for Gauges
Circular Gauges
Linear Gauges
Knob Control
Radial Menu
Rotation Control
Numeric Indicators
Color Indicators
Text Labels
Image Indicators
Analog Clock
Gauge Containers
Windows UI-style Tiles control
General Win UI-style Tiles control features
WinUI-style Tile Objects
WinUI-style Tile Badges
Diagram Control
General Diagram Control Features
Diagram Block Types
Miscellaneous GUI Controls
Property List (Grid) Control
Hyperlink control
Enhanced pushbutton
Menu button (Split button)
Advanced Tab Control
Microsoft Office-style color picker
Brush button
Advanced animation control
Microsoft Visual Studio-style editable list box
List header control
Font picker
Masked edit control
Date/Time control (date-time picker)
Calendar control
Duration control
Images with hot-spot areas
Edit control with a browse button
Calculator
Popup (Desktop Alert) Window
Tooltip Control
Breadcrumb Control
Tag Cloud Control
TreeMap Control
Dialogs
Skinned Dialogs and Forms Support
Resizable Dialogs and Forms
Advanced Property Sheet
Aero Wizard
Toolbar Customization dialog
Image Edit dialog
Brush Edit dialog
Text Format dialog
Office-like color selection dialog box
Key Map Dialog
Windows Management dialog
Textured dialogs
Enhanced file dialog box
Advanced Message Boxes
Progress ("Wait") dialog
Visual Studio Integration
Application Wizard
Integration Wizard
Build Wizard
MSDN-integrated Help
Shell Management
Shell management classes
Shell tree, list and breadcrumb controls
Windows 7 Taskbar Integration
Miscellaneous
Drawing manager
UNICODE support
High DPI Support
Microsoft Active Accessibility Support
Right-to-Left Languages Support
Localization
 

반응형
반응형

http://blog.naver.com/mcblagg?Redirect=Log&logNo=10027082656


operator new란 무엇인가? 쉽게 말해서 객체를 생성하기는 하는데, 다른 요소는 몽땅 무시하고 메모리 공간만 그냥 잡아준다는 말이다. 물론 생성자도 호출되지 않는다.

 

선언방식은 매우 간단한다. 연산자 정의만 새로 해주면 끝.

void* operator new(size_t size); // size크기만큼 메모리를 잡아주고 메모리 포인터를 넘겨준다.

 

사용법은 더 간단하다. 스트링 객체를 생성해보자.

 

void* stringClass = operator new(sizeof(String));  // operator new를 이용한 메모리 공간 할당

void* stringClass = malloc(sizeof(String)); // malloc을 이용한 메모리 공간 할당

 

결국 두가지 방법 모두 똑같은 형태란 얘기다. 클래스 크기만큼의 공간만 할당해줬을뿐. 엄청 쉽다.

 

 

 

그렇다면 이젠 메모리지정 new, placement new 에 대해서 알아보면 되겠다.

 

우리가 위에서와 같이 그냥 메모리 공간만 할당해 놓았다면,

 다시 말해서 초기화가 되지 못한 메모리 상태라면,

 생성자를 호출해 버리고 싶은 욕구를 떨쳐내기 힘들 것이다. 크.. 당연한 얘기다.

 

그래서 필요한 게 메모리지정 new다 쉽게 말하자면 이미 잡혀있는 공간에 생성자를 불러준다는

뜻으로 생각하면 쉽겠다.  준비과정으로 무엇이 필요할까?

 

1. 잡아놓은 메모리공간

2. 생성자에서 필요로하는 매개변수들

 

이 두놈들만 있으면 준비는 끝이다. 이제 사용방법에 대해서 알아보자.

 

우선 operator new를 새로 정의해주자.

void* operator new(size_t, void* location) {

   return location;

}

위 정의에서 보면 알수 있듯이 인자로 받은 포인터를 고스란히 넘겨주도록만 정의해주면 끝이다.

 

그럼 실제로 적용해보자.

 

Book이라는 클래스가 있다고 가정하고, Book(string title)이 매개변수 생성자라고 하자.

 

ConstructBook(void* book, string title) {

   return new (book) Book(title);

}

 

이렇게 정의한 ConstructBook 함수가 바로 메모리 지정 함수다.

지정된 메모리(void* book)가 넘어오고 이 메모리에 생성자가 다시 호출되고 있다.

 

결과를 확인해보면 이 함수를 통해 공간만 할당되었던 book의 메모리에 인수로 받은 title이

새롭게 지정된 것을 확인할 수 있을 것이다.

 

정리를 해보자면.

 

1. new는 힙에 메모리를 할당함과 동시에 초기화를 해준다.

2. operator new는 힙에 메모리를 할당은 하지만 초기화는 해주지 않는다.

3. 메모리지정 new는 초기화 되지 않은 힙에 있는 메모리를 초기화 할 수 있게 해준다.

반응형
반응형




http://blog.naver.com/kkss2013/60108816896




gpg study를 돌아다니다가 우연히 보게 된 기법..

클래스의 헤더에 변수는 내부에서만 사용하는 변수가 많은데

그것들을 외부로 보여지지 않게 하는 기법이 있어서 잠깐 구현방법을 확인해봤습니다.

 

우선 장점을 보면

: 클래스의 내부 변수를 외부에서 접근 및 확인 하기 어렵다.

: 내부 변수를 추가할때 헤더 파일에 추가하지 않아도 된다.(다른 헤더를 빌드할 필요가 없다!!)

 

단점은

 : 내부변수를 new로 생성해야 하기 때문에 속도상의 문제가 조금있지 않을까 싶기도 하네요 ..

 : 인라인 함수를 만들 수 없다는점도 .....

 

구현방법을 간단히 보면

 

 // 헤더 파일

 

#pragma once


class CPimpl

{

public:

 CPimpl(void);

 ~CPimpl(void);

protected:

 struct XImpl;  // 맴버변수의 구조체 전방선언

 XImpl* pimpl_;  // 맴버변수의 포인터

public:

 int GetType();

};

 

 

 


 

// cpp 파일

#include "Pimpl.h"

// 맴버 변수는 여기에 추가 합니다.

struct CPimpl::XImpl 

{

 int m_nType;

 // 초기화 코드 추가

 XImpl()

 {

  m_nType = 0;

 }

};


CPimpl::CPimpl(void)

{

 pimpl_ = new XImpl;

}

CPimpl::~CPimpl(void)

{

 delete pimpl_;

}

int CPimpl::GetType()

{

 pimpl_->m_nType = 10;

 return pimpl_->m_nType;

}


 

반응형
반응형
C++에서 동적 객체를 생성하기 위해 일반적으로 new 연산자를 사용하는데, new 연산자는 2가지의 동작단계를 지니고 있습니다.

  • 요청한 타입의 객체를 담을수 있는 크기의 메모리를 할당한다.
  • 객체의 생성자를 호출하여 할당된 메모리에 객체의 초기화를 수행한다.

new 연산자의 첫번째 동작단계, 즉 요청한 타입의 객체를 담을수 있는 크기의 메모리 할당은 내부적으로 operator new 라는 함수를 호출하여 이루어집니다.
 
 void * operator new(size_t size)

operator new함수의 반환타입은 void * 입니다. 즉, operator new는 malloc함수와 마찬가지로 메모리만 할당하는 것뿐입니다. 객체니 생성자니 하는것은 operator new와는 전혀 관계없는 것들일뿐이며, 할당된 메모리를 받아 온전한 객체를 생성하는 것은 new 연산자의 몫입니다.
 
우리는 new 연산자에 대해 재작성이나 오버로딩을 할 수 없지만, operator new 연산자는 재작성, 오버로딩을 할 수 있는데 이를 통하여 자신만의 커스터마이징된 메모리 관리 시스템을 개발할 수 있습니다.(operator new를 오버로딩 할 때에는 size_t이외의 매개변수를 추가할 수 있는데, 이럴때도 첫번째 매개변수는 언제나 size_t 타입이여야 합니다.)
 
 
1. placement new
operator new(또는 malloc)을 통해 할당은 받앗지만 초기화되지않은 메모리가 있을때, 우리는 바로 이 메모리 위해 객체를 초기화시킬 수 있습니다. 이를 placement new라 합니다. placement new를 실행하기 위해 준비해야할것은 #include<new>를 추가하는 것이 전부입니다.
  1. MyClass *mem = static_cast<MyClass*>(operator new(sizeof MyClass));  
  2. new (mem) MyClass();  
위 코드에서 new (mem) MyClass() 부분이 placement new 연산자 입니다. 문법이 조금 이상하지만 operator new 연산자에 매개변수가 1개 더 추가 되었다고 보면 됩니다.

 void * operator new(size_t, void *location)
new, operator new, placment new에 대해 정리하면 다음과 같습니다.
 
  • 어떤 객체를 heap에 생성하기 위해서는 new 연산자를 사용합니다.
  • 메모리만을 할당하고 싶을 경우에는 operator new 함수를 사용합니다. 즉, 만약에 heap 객체의 생성을 도맡는 메모리 할당 매커니즘을 손보고 싶다면, operator new를 직접 작성하면 됩니다. new 연산자는 operator new 함수를 호출하게될 것이며 호출된 operator new함수는 개발자가 새롭게 작성한 함수입니다.
  • heap에서 직접 메모리를 가져오지 않고, 개발자가 지정한(이미 가지고 있는) 메모리를 사용하게 하려면 placement new를 사용합니다.
 
 
2. delete, operator delete
메모리 누수를 막기 위해서는, 할당한 메모리는 반드시 그에 대응되는 메모리 해제를 통해 운영체제에 돌려줘야 합니다. C++에서는 기본적으로 제공되는 delete 연산자를 사용하게 됩니다. 그런데 delete 연산자도 new 연산자와 마찬가지로 내부적으로 어떤 함수를 호출하게 되있습니다.
 
 void operator delete(void *dealloc)
 
new 연산자를 통해 할당된 메모리는 delete 연산자를 통해 해제해야합니다. delete 연산자는 객체의 소멸자를 호출하고 객체가 차지하고 있던 메모리를 운영체제에 반환하게 됩니다.
 
여기서 주의해야할점은, 미초기화된(객체가 생성되지 않은) 메모리를 가지고 어떤 일을 할때에는 new와 delete 연산자를 사용하지 않아야 합니다. 그 대신 메모리를 얻을때에는 operator new를 메모리를 해제할때는 operator delete를 사용합니다.(마치 malloc함수를 통해 할당된 메모리를 free함수를 통해 해제하는것처럼)
 
placement new를 사용한 경우에는 절대로 delete 연산자를 호출하면 안됩니다. 이유는 delete 연산자는 operator delete를 호출하여 메모리를 해제하지만, placement new에서 사용된 메모리는 원천적으로 operator new를 통해 할당된 것이 아니기 때문입니다. 대신 객체의 소멸자를 직접 호출해주고 메모리도 역시 직접 할당한 방법에 따라 해제해줘야 합니다.
  1. MyClass->~MyClass();  
  2. operator delete MyClass;  
이와 같이 C++에서 기본 제공하는 new, delete 연산자의 동작방식을 직접 손댈수는 없지만 이들 연산자가 내부적으로 호출하는 operator new, operator delete 연산자는 개발자가 마음먹은대로 고칠 수 있으며, 이는 프로그램의 전첵 메모리 할당 매커니즘을 총괄하는 강력한 메모리 매니지먼트 시스템을 개발할 수 잇음을 의미합니다.

 

예시

 

 

 

http://lyb1495.tistory.com/48

 

반응형
반응형

http://www.gpgstudy.com/forum/viewtopic.php?p=49015






C++에서는 메모리 구조 측면에서 두 종류의 object를 갖습니다. 

하나는 C의 structure나 built-in type과 동일한 메모리 구조를 갖는 object이고 다른 하나는 다형성이나 생성/소멸자 등등의 특성을 사용할 수 있는 object입니다. 전자를 Plain Old Data(POD)라고 하고 후자를 non-POD라고 합니다. 


POD object는 C의 구조체처럼 똑같이 사용할 수 있습니다. memcpy나 memset 등을 사용할 수 있습니다. POD 의 조건은 아래와 같습니다. 

1. built-in type 

2. 가상 함수를 가지지 않으며 사용자 정의 할당자와 소멸자를 가지지 않은 class의 object 

3. non POD를 non-static 멤버로 가지지 않은 class의 object 


위 조건만 만족한다면 C의 struct처럼 object를 사용해도 괜찮습니다.






전송 구조에선 아무래도 메모리로 관리해 주는 게 편할 것 같아서 좀 고민했거든요... 
근데 POD의 조건으로 나와 있는 3가지 항목을 보니, 

1번은 기본 멤버 변수 타입을 요구하는 것 같고 
2번은 생성, 소멸자 및 가상함수 같이 유저 외에 컴파일러가 따로 처리해야 하는 부분이 없어야 하며 
3번은 사용자 정의 타입이나 함수의 사용에 있어서는 static으로 사용될 용량을 도출해 낼 수 있어야 한다... 

란 의미인 걸로 우선 해석되는데, 방향을 제대로 잡았나요? 
어차피 int하고 float, char의 멤버 변수로만 구성된 struct를 쓸 예정이긴 합니다만...;;







C의 구조체와 같은 배치와 사용법을 가지는 C++의 구조체, 클래스는 다음과 같은 조건을 가져야 합니다. 


A. built-in 타입, 또는 다른 POD타입만을 멤버로 가질 것. 

B. 가상함수가 없을 것. 


부연하자면, 

A. 말씀하신 조건중 1번과 3번은 사실상 같은 내용입니다. POD타입은 built-in 타입과 같이 쓸 수 있는 타입을 말하므로 어떠한 것이 오더라도 상관이 없습니다. 또한, 스태틱 멤버는, 당연히 아시겠지만, 객체에 포함되는 멤버가 아니므로 POD이건 non-POD이건 무엇이 오건 영향을 미치지 않습니다. 

B. 가상함수만 없다면, 생성자(constructor)와 소멸자(destructor)는 있건 없건 메모리 배치에 영향을 주지 않습니다. (물론, 가상소멸자는 가상함수에 포함됩니다) 사용자 정의 할당자(allocator) 역시 정의되어 있건 아니건, 할당 위치에 영향을 미칠 뿐, 객체 내부의 메모리 배치에는 영향을 주지 않습니다. RTTI역시 메모리 배치에 영향을 주긴 하지만, 가상함수가 없는 타입의 객체에는 RTTI가 포함되지 않으므로 가상함수를 안쓴다면 신경 안써도 됩니다.

반응형
반응형

콜라다 홈피
https://collada.org/

콜라다 다운받을 수 있는 주소
https://code.google.com/p/opencollada/




http://wrice.egloos.com/5027746

Collada 소개와 책 추천
제가 Collada 를 공부해야겠다고 생각하게 된 계기는 첫번째로, Gamasutra 에서 구인 광고 할때  Collada 경험자를 선호한다는 것을 몇번 보아왔기 때문이고, 둘째는 PhysX 문서를 읽던중에 Collada 가 몇번 언급 되었기 때문입니다,

생소할수 있는 기술인 Collada 를 한마디로 요약하면, Max/Maya exporter 라고 할수 있겠습니다. 흔히 게임 개발자들이 Max 에서 생성된 데이터를 게임에서 불러와서 화면에 보여주려면 Max 용 plug-in 을 직접 작성해야한다고 알려져 있습니다. 그리고 이 plug-in SDK 를 사용해서 exporter 를 만드는게 쉽지 않습니다. 한국에서 특히 많이 팔린 GameBryo 라는 게임 엔진이 선호되는 많은 이유들 중의 하나가, 안정적인 Max exporter 를 제공하기 때문입니다.

Max/Maya 를 사용해서 파일을 저장할때 binary 파일로 저장을 하게 되면 그걸 읽어서 게임에서 불러 들여서 사용하면 참 행복하겠지만, Max/Maya 내부에서 사용하는 데이터 포멧을 일반 프로그래머들이 이해하기란 시간이 너무 많이 걸리고, 버전이 올라갈때마다 갱신해야한다는 문제점이 있습니다. 그래서 Max/Maya 의 개발자용 SDK 를 사용해서 export 할수 있도록 exporter 를 개발해서 사용하게 되는 것입니다. 그러면 자신의 게임에 필요한 정보만 뽑아내서 외부 파일로 저장하는것이 가능해집니다.

exporter 를 만드는것이 부담되는 경우에 흔히 택하게 되는 차선책은 ASE 파일 포멧입니다. 이것은 사람이 읽을수 있는 형태의 ascii 파일 형태이기 때문에 적절한 파서를 만들어서 사용하기 용이 합니다.

exporter 를 만들지 않을 경우 또 한가지 고려할수 있는 선택지는 .X 파일입니다. Microsoft 에서 개발한 자체 포멧인 X 파일을 사용하면 따로 파서를 만들 필요도 없이 바로 게임에서 사용이 가능하고 LOD 같은 훌륭한 기능도 덤으로 사용할수 있게 됩니다.

그런데 ASE 와 X 파일에는 한계가 있어서, 상용 게임을 개발하고자 할때에는 이 둘중의 어느것도 사용할수가 없습니다. 특히 문제가 되는 것은 "에니메이션"입니다. 게임에서 사용하는 에니메이션은 Skeleton 이라는 데이터 구조를 사용하는 방식인데, 이것을 지원하지 못하기 때문입니다.

에니메이션 이외에도, Occlusion culling 에 사용할수 있는 Scene Graph 지원이 안되고, Physics 연동이 안되어서 게임 프로그래머가 직접 구현을 해주어야 한다는 한계도 있습니다.

Collada 는 이런 문제점들을 모두 개선할 목적으로 개발된 XML 표준안입니다. Max/Maya 에서 Collada 포멧으로 파일을 저장하면 text 형태로 사람이 읽어볼수 있도록 XML 로 저장이 됩니다. 그리고 이렇게 저장된 데이터에는 Geometry 정보, Scene, Animation, Physics 정보등이 모두 포함되어있습니다. 거기에 더해서 Max 에서 저장한 Collada 파일이 Maya 에서도 불러와서 수정할수 있도록 상호호환이 가능합니다.

Collada 는 XML 표준안일 뿐이기 때문에 실체를 갖은 소프트웨어는 없다고 볼수 있겠습니다. 하지만 Collada 를 밀어주고 있는 Sony 에서 Collada DOM 이라는 소프트웨어를 개발해서 제공하고 있고, XML schema 의 문법이 아주 잘 완성되어있기 때문에 이것만으로도 충분히 실용성을 가지고 있다고 할수 있겠습니다.

저는 Collada 검색어로 Amazon 에서 이 책(Collada: Sailing the Gulf of 3d Digital Content Creation)이 검색 되길레 일단 별다른 기대없이 도서관에서 빌렸습니다. 그런데 책이 상당히 좋았고, Collada 에 대한 아무런 배경 지식이 없었는데 많은 것을 얻을수 있었습니다. 사실 Collada 관련 정보는 입수하기가 매우 어려웠고, 입문자를 위한 자료로는 이 책이 거의 유일한것 같습니다. (그래서 그런지 얇은 책임에도 불구하고 비싸게 팔더군요...)

간단히 요약하면 다음과 같습니다.
1장: 소개
Collada 의 개발 배경과 간단한 역사(?)가 설명됩니다.

2장 : Collada Document
Collada 와 XML 표준과의 연관 관계를 설명합니다.

3장 : Collada Geometry
Collada 내부에서 기하 도형을 어떻게 표현하는지 설명합니다.

4장 : Collada Scene
Collada 내부에서 Model 의 Local/World 좌표계 표현을 어떻게 하는지 설명합니다. 그리고 각 node 간의 종속 계층 관계를 어떻게 표현하는지도 설명합니다.

5장 : Collada Effect
Collada 파일 안에 Shader 코드를 어떻게 집어 넣는지 설명합니다. Collada Effect 는 Collada FX 라고 부르기도 합니다. 책의 설명에 따르면 NVidia 에서 개발한 FX Composer 의 표멧과 거의 같다고 하는데, 제가 FX Composer 를 안써봐서 잘 모르겠습니다. DX 에서 사용하는 Effect Framework 의 약간 변형된 형태와 같다고 볼수 있겠습니다.

6장 : Collada Animation
Collada 에서 Skinning 와 Morphing 을 어떻게 표현하는지 설명합니다.

7장 : Collada Physics
Collada 에서 물리를 어떻게 표현하는지 설명합니다. Rigid Body 밖에 아직 지원하지 않는듯 합니다. 대부분의 내용은 PhysX 개발자들의 영향을 받았다고 합니다.

8장 : Collada Contents Pipeline
Collada 의 Conditioner 와 Refinery 의 개념을 설명하고 앞으로 개선 방향을 제시합니다.
책 자체는 매우 작은 헨드북 수준의 책입니다. 뒤의 별 내용없는 부록 부분을 제외하면 160페이지 정도 밖에 되지 않습니다. 저는 읽는데 2일 걸렸습니다.

읽고나서 소감은, 앞으로 조만간 Collada 가 대세가 되겠다는 생각이 들었습니다.

책은 1.4 버전을 기준으로 입문자를 위해서 만들어진 책입니다. Collada 웹 사이트에 가보면 지금 1.5 버전의 표준안이 공개되어있어서 다운 받을수 있습니다. 200 페이지가 넘는 표준안 문서가 공짜로 공개되어있는 상황인데, 그래도 그 표준안은 입문자를 위한 수준이 아니어서 이 책을 먼저 한번 읽어주고 표준안을 보면서 코딩하는게 좋겠다는 생각입니다.

그리고 한편으로는 GameBryo 는 이제 뭘로 먹고 사나 하는 생각이 들었습니다. 물리는 PhysX 구현에 의존하고, 소리는 마일드에 의존하고, 유일하게 강점이었던 SceneGraph 랑 Max Exporter 도 이제 Collada 가 대세가 되면 Collada 에 의존하게 될텐데....;;;

트랙백 주소 : http://wrice.egloos.com/tb/5027746
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
 Tracked from bt22d's me2DAY at 2009/10/07 11:22

제목 : 헌신랑의 생각
쌀밥게임 대왕 : Collada 소개와 책 추천...more

 Commented by 쌀밥 at 2009/08/01 04:14 
AutoDesk 에서 개발한 FBX 라는 파일 포멧도 있군요:
http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=6837478
 Commented by 쌀밥 at 2009/08/01 06:01 
Collada Official Viewer 라는것이 있군요.
http://www.feelingsoftware.com/content/view/40/66
이름이 Feeling Engine 이라고 합니다.. (근데 상용이군요...)

무료도 있는데 제대로 돌아가는지는 모르겠군요.
http://wiki.worldforge.org/wiki/Collada
 Commented by MuMbi준환 at 2009/08/03 16:37  
저도 쌀밥님과 같은 생각입니다. 

현재 취직하기 위해 포트폴리오를 제작하기 위해 exporter 를 제작하려고 자료를 찾아보다가 collada 를 알게 되어 막 개발에 들어갔습니다. 

collada 가 3d model 표준 이라는 말이 가장 많은 매리트였고 
웹 3D 를 구현한 google 이나 flash 3D library 에서도 collada 를 사용한다고 알게 되어 collada 를 사용하여 구현하려고 합니다.

그런데 우리나라에는 collada 에 관련된 자료가 많지 않아 이렇게 검색하다가 블로그에 들리게 되었네요. ^^;

저는 현재 feelingsoftware 에서 제공하는 FCollada library 를 사용하여 개발 중입니다. 

시작부터 삽질이 많네요.

좋은 정보 많이 알아갑니다.

추천 하신 책은 꼭 읽어봐야겠네요. 

즐거운 하루 되세요 ^^
 Commented by MuMbi준환 at 2009/08/03 16:44  
아, 저 책 어디서 빌릴 수 있을까요?
 Commented by 쌀밥 at 2009/08/08 14:32 
책은 생각보다 얆고 괜찮은 편입니다. 좀 비싸기는 하지만 하나 장만하시는게 좋겠다는 생각입니다. 워낙에 보는 사람이 없어서 빌리기가 어렵습니다.

그리고 FCollada 는 안써봐서 잘 모르겠지만 ColladaDOM (공식 라이브러리) 만으로도 충분히 좋다고 생각합니다. SVN 으로 최신버전 (2.2)을 받으시면 제대로 컴파일되고 돌아가는 viewer 로 얻으실수 있습니다. Open source 로 개발되고 계속 업데이트도 되고 있는 중이라서 좋습니다. FCollada 는 업데이트가 중지된지 꽤 된걸로 알고 있습니다.
 Commented by MuMbi준환 at 2009/08/20 09:09  
아 좋은 정보 감사합니다. 

어쩐지 FCollada 는 1.4 버전이 끝이더라구요.. 

ColladaDOM 으로 다시 해야겠네여 ㅎ
 Commented by STL at 2010/01/28 22:33  
좋은 정보 담아가겠습니다~
 Commented by 쌀밥 at 2010/01/29 12:54 
Sony PS3 SDK 설치하니까 Collada XML Loader 도 같이 설치 되더군요...
 Commented by 초보 at 2010/08/24 07:23  
정보감사합니다.
x파일로 포폴만드는중인데 collada 로 만들고싶은 생각이
확듭니다. 그나저나 초보들은 너무힘이듭니다.
이거찔끔저거찔금 하다 시간다가네요.ㅠㅠ
 Commented by 쌀밥 at 2010/08/27 17:43 
회사에서 일하기 시작하면 찔끔 거릴 시간 조차 없는것 같아요...

x 파일도 좋은데 collada 가 x 파일보다 강점인것은 애니메이션을 지원할수 있다는 점입니다. 근데 저도 아직 애니메이션을 지원하는것 까지 구현하질 못했습니다.

물리 엔진을 사용하시면 애니메이션 구현이랑 연동 시키는 부분에서 어떻게 구현할지 정해야할 텐데, 구부분을 잘 고려해보시고 물리엔진만으로 애니메이션이 커버 될것 같으면 그냥 X 파일로 가시는 것도 한가지 방법이겠습니다.

시작하는 초기 단계라면 계획을 너무 무리하게 잡고 시작하는 것은 좋지 않을것 같아요. 게임 프로그래밍은 만만한게 아니니까요 ㅎㅎ
 Commented by 기쿤 at 2011/01/28 14:41  
.x 파일도 skeleton animation을 지원하는거 아닌가요?
그.. tiny.x 도 그럴텐데;;
 Commented by 쌀밥 at 2011/01/31 18:49 
기쿤// 다시 검색해보니 X 파일도 키를 사용한 애니메이션이 되는군요.
http://msdn.microsoft.com/en-us/library/bb172239%28v=vs.85%29.aspx
 Commented at 2012/02/19 08:33  
비공개 덧글입니다.

반응형
반응형

http://anster.egloos.com/2165172



오늘, 그리고 지난 주 금요일은 하루종일 압축 라이브러리와 씨름했다.

맨 처음에는 Zip으로 압축할려고 찾아봤더니, Zlib를 약간 개량한 Zziplib 란게 나왔는데,, 도저히 빌드 못하겠다.. 그래서 포기.

Zlib 는 사용할려고 기껏 빌드했더니,, 유니코드 지원이 안되더라. 

그래서 구글에서 유니코드를 지원하는 zlib 검색을 해보니 코드프로젝트에 등록되어있는 CGzip이 나왔다. 오. 사용법도 쉽고 간단하구만,, 해서 받고 압축 풀고 각종 에러를 해결하고 빌드하니 파일 하나만 압축이 가능하댄다 -_-; 제작자가 시간이 없어서 여러개를 압축하는데까지는 신경을 못썼댄다.

결국 코드프로젝트에서 LiteZip 이란 라이브러리를 찾아냈다. 찾아내서 압축을 풀고 보니 VC++ 5.0 프로젝트 워크스페이스가 나온다.
2010으로는 바로 변경 불가 -_-; 그래서 6.0으로 변환 후 다시 2010으로 변환. 

파일 내부의 소스를 보니 WIN32인 경우와 아닌 경우를 나누어 놓았던데,, 리눅스 호환 라이브러리다. 윈도우와 리눅스의 경우 두 경우 모두 컴파일 할 수 해 놓은 라이브러리인데, 굉장히 정교하게 짜여졌다는 느낌을 많이 받았다. 나도 이렇게 유용하고, 잘 설계된 라이브러리를 만들고 싶다.^^


아참, 그리고 LiteZip.h 에 다음과 같은 문장을 추가 해 주어야 한다.

// Edited 2011. 07. 18 By Anster.
// Functions for adding a "Directory" to a ZIP archive

DWORD WINAPI ZipAddDirA(HZIP, const char*, DWORD);
DWORD WINAPI ZipAddDirW(HZIP, const WCHAR* DWORD);

#ifdef UNICODE
#define ZipAddDir ZipAddDirW
typedef DWORD WINAPI ZipAddDirPtr(HZIP, const WCHAR*, DWORD);
#define ZIPADDDIRNAME "ZipAddDirW"
#else
#define ZipAddDir ZipAddDirA
typedef DWORD WINAPI ZipAddDirPtr(HZIP, const char*, DWORD);
#define ZIPADDDIRNAME "ZipAddDirA"
#endif

이 라이브러리의 설계자가 후에 디렉터리를 압축하는 함수(ZipAddDirA, W)을 라이브러리에 추가하면서
라이브러리에 함수를 익스포트 해 놓았으나 헤더파일에는 원형을 추가하지 않아서 사용하려면 빌드 에러가 난다.



2011. 7. 19 추가 

-_- 사용하다보니, 멀티바이트 버전의 ZipAddDirA 는 잘 작동하는데, ZipAddDirW 가 작동하지 않는다. 라이브러리를 내가 직접 고쳐서 써야하는것도 정말 너무너무 귀찮고 -_-;; 찾다보니 라이브러리가 아니라 CPP와 헤더파일로 첨부만 해서 함수를 사용하는 

Zip Utils 를 찾아냈다. zip_utils_src.zip

Clean, Elegant, Simple 한 C++/Win32 라이브러리라는데,, 이거마저 안되면 다른걸 또 찾아야된다 -_-


참고 - CGzip Lib http://www.codeproject.com/KB/cpp/cgzip.aspx
         LiteZip LIb http://www.codeproject.com/KB/library/LiteZip.aspx
         Zip Utils http://www.codeproject.com/KB/files/zip_utils.aspx
         Zip http://www.codeproject.com/KB/recipes/zip.aspx
         Boost Gzip http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/classes/gzip.html
         Boost Zlib http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/classes/zlib.html
         Boost Bzip2 http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/classes/bzip2.html#examples
         Minizip http://www.winimage.com/zLibDll/minizip.html
         Minizip Example http://ddiggam.tistory.com/5

2011. 07. 21 추가

Zlib 압축 알고리즘과 Zip(PKZIP) 압축 알고리즘이 같아서 헤더 포맷만 맞추어주면 Zlib를 Zip 압축에 쓸수 있다고 한다.

참고 -  http://www.google.co.kr/url?sa=t&source=web&cd=3&ved=0CD0QFjAC&url=http%3A%2F%2Fkldp.org%2Fnode%206&ei=1LknTpmkAeydmQWMkvH_CQ&usg=AFQjCNF_WrrqYyFQRCWOYmAvk6wfpSADiQ

그리고 ZIP Utils 을 사용해서 압축을 하면 한글 파일과 폴더가 이상한 이름으로(like as 꽯꽥) 압축이 되는데, 

이는 헤더인 zip.h 와 unzip.h 를 수정하면 된다. CP_UTF8 -> CP_OEM 으로 변경하자. 

아래는 폴더를 압축하기 쉽게끔 만든 파일이다. 

CompressDirectory.cpp

다음과 같이 사용하면 된다.


#include <stdafx.h>
#include <zip.h>

BOOL SetCompressDirectory (HZIP* phZip, LPTSTR pszCompressPath, LPTSTR pszZipCreationPath, LPTSTR pszZipName );

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc < 4)
        return 0;

    HZIP hZip;

    if ( !SetCompressDirectory ( &hZip, argv[1], argv[2], argv[3] ) )
        _tprintf ( _T("FAIL\n") );
    else
        _tprintf ( _T("SUCCESS\n") );

    return 0;
}


반응형
반응형

http://developinghappiness.com/?page_id=222


Make 기반 빌드 시스템

차례

예제 파일 다운로드 및 실행

make (버전 3.80 이상), gcc 및 mercurial이 설치된 리눅스에서는, 해당 포스트에서 다룬 내용의 예제 Makefile 및 소스 파일들을 다운로드 받아서 직접 실행해 보실 수 있습니다.

처음으로 다운로드 받을 때에는 hg clone을 사용합니다.

추후 글이 추가되거나 수정되면서, 관련 예제  파일들이 변경된 내용을 업데이트 하고 싶을 때에는, hg pull 명령어를 사용해서 타이핑 횟수를 줄일 수 있습니다.

예제 파일들을 다운로드 받은 이후에는, 해당 Chapter 디렉토리로 이동해서 make의 -f 옵션으로 실행할 Makefile 이름을 지정해서 해당 Makefile로 make를 실행할 수 있습니다. 예를 들어 Chapater3 의 예제 3.4 를 실행하시려면 다음과 같이 하면 됩니다.

Chapter7 부터는 빌드 디렉토리 구조가 정해진 관계로, 빌드하기 전에 $PROJ_ROOT 환경 변수가 올바르게 이루어져 있어야 하기 때문에, 다음과 같이 해 주셔야 합니다. ($PROJ_ROOT 가 설정되지 않은 상태에서 빌드를 실행하면, 빌드에 필요한 공용 include 파일을 찾지 못하겠다는 에러 메지시자 나옵니다.)

Chapter9 부터는 공유 라이브러리가 지원됩니다. 공유 라이브러리를 링킹한 응용 프로그램을 실행할 때에는, 실행 전에 해당 공유 라이브러리가 지정된 디렉토리를 LD_LIBRARY_PATH 환경 변수를 지정해야 합니다. 만약 디버그용(make 실행 시 RELEASE=1 없이 실행)으로 빌드한 경우라면 다음과 같이 설정해 줍니다. (릴리즈용을 실행하는 경우에는 Debug 대신 Release 로 설정해 줍니다.)

 

반응형
반응형

http://developinghappiness.com/?p=26


Make 기반 빌드 시스템 (1): 빌드 시스템?

빌드 시스템?

기본적으로 하나의 프로그램은 수 많은 소스코드들로 이루어져 있고, 규모가 커지면 여러 가지 모듈 또는 라이브러리들로 나누어지게 됩니다. 따라서 작성된 소스 코드로부터 최종 결과물들을 빌드하는데 시간도 많이 걸릴 뿐 아니라, 경우에 따라서는 여러 가지 환경과 옵션에 따라 다르게 빌드할 필요도 생깁니다. 효율적으로 개발하기 위해서는 의존성 관계를 잘 추적해서 그중 일부가 수정되면, 수정된 소스 파일들과, 그 수정으로 인해 변경되어야 하는 소스 파일들만 새로 컴파일 하는 기능도 꼭 필요할 겁니다.

이런 점들을 고려한 통합 개발 환경(Integrated development environment, IDE)은 예전서부터 있어 왔고, 요즘은 정말 훌륭한 툴들이 많이 있습니다. IDE를 사용하면 소스 코드 편집, 빌드, 실행 및 디버깅을 하나의 프로그램 내에서 편리하게 진행할 수 있습니다. 당연히, 의존성에 따라 꼭 필요한 파일들만 다시 빌드 해주는 식으로 빌드 옵션 관리도 똑똑하게 해 줍니다. 심지어는 코드를 수정해서 저장하자 마자, 백그라운드로 빌드해 주기도 하죠.

하지만, 어떤 경우에는 적절한 IDE가 없을 수도 있고, 경우에 따라서는, 예를 들어 일일 자동 빌드를 하는 경우에는, IDE가 오히려 불편할 수 있습니다. 그래서 좋은 개발 도구들은 GUI 기반의 IDE와 함께, 도스나 터미널 같은데서 명령어 기반으로 빌드할 수 있는 기능을 같이 제공하더군요.

그러나 어떤 이유에서였든, GUI 기반의 IDE 없이 개발해야 한다면, 그럼 도대체 어떻게 그런 똑똑하고 효율적인 빌드를 수행할 수 있을까요… 불행히도 없습니다… (응?) 농담입니다. 다행히도, 그런 운 나쁜(?) 개발자들이 의지할 수 있는 친구들이 몇 있는데요, 그 중 하나가 make입니다.

make는 주어진 규칙에 따라 작성된 입력 파일의 내용에 따라 주어진 일을 자동으로 수행하는 유틸리티입니다. 사실 make를 이용해서 여러 가지 작업들을 할 수 있겠습니다만, 소프트웨어 개발자 입장에서 보면 소스 코드를 컴파일하고 링킹해서 최종 결과물을 만드는데 없어서는 안 되는 도구입니다.

참고로 GNU make는 GNU에서 구현한 make이고요, 일반적인 리눅스에는 기본으로 포함되어 있거나 적어도 쉽게 무료로 설치할 수 있습니다. gmake라고도 하죠. 유닉스나 BSD나 기타 다른 OS에서는 gnu make와 다른 make가 있을 수 있는데요, GNU make는 다른 make들에 비해 대부분의 기능 면에서는 문제없이 호환되지만, 자체 확장 기능도 가지고 있습니다. 제 글에서는, 리눅스에서 GNU make를 사용하는 것을 전제로 하기 때문에, GNU make를 그냥 make라고 통칭하도록 하겠습니다.

make에 관련된 가장 훌륭한 레퍼런스는 당연히(?) GNU 사이트의 make 문서입니다.

  • http://www.gnu.org/software/make/manual/make.html: Makefile을 수정하다가, 뭔가 추가로 이런 기능이 있지 않을까? 또는 다른 사람이 작성한 Makefile을 참고하는데 이 내용은 도대체 뭘까? 하는 의문이 들때 결국 찾게 되는 사이트입니다. (단, 영어 실력이 좀 받춰줘야 합니다.)
  • 위 Make 매뉴얼 한글판은 http://www.viper.pe.kr/docs/make-ko/make-ko_toc.html 에 있습니다. (Taehun Kim 님께서 알려 주셨습니다. 아무래도 영어가 부담스러운 사람에게, 위 make 매뉴얼 페이지의 빠르게 내용을 파악하는데 큰 도움이 될 수 있겠네요.

앞으로 쓰는 글에서도 나름 설명하겠지만, make의 기본을 좀 속성(?!)으로 이해하려면, 다음 사이트들의 내용이 큰 도움이 됩니다. 고맙게도 한글로 잘 정리되어 있습니다.

리눅스 쪽 개발 작업에서는 많은 경우 make를 사용합니다. 그리고 생산성과 품질을 중요시하는 제대로 된 개발팀이라면, 다음과 같은 작업이 가능한 빌드 시스템 및 Makefile 파일을 작성하는 고유의 규칙을 가지고 있을 겁니다.

  • 하나의 소스 트리에서 여러 가지 타겟 플랫폼들을 단일 명령으로 빌드할 수 있고,
  • 특정 타겟 별로, 그리고 각 모듈 별로 필요한 빌드 옵션을 적용할 수도 있고, 모든 플랫폼과 모듈들에 동일한 옵션을 한번에 적용할 수도 있으며,
  • 나아가 최종 실행 라이브러리들과 실행파일들을 한방에, 즉 명령어 하나의 입력이나 단축키 하나 누르는 걸로 만들어 내고, 자동화된 단위 테스트(unit test)들을 실행해 낼 수 있습니다.

하지만 늘 해야할 일에 비해 개발인력은 부족한 개발팀에서, 이런 환경을 갖추기란 쉽지 않습니다. 특히나 (제가 주로 몸 담아온 회사들처럼) 규모가 작은 중소기업이라면, 그리고 개발하는 소프트웨어 그 자체로, 돈을 벌어주는 최종 제품이 되는 것이 아니라, 어떤 HW 제품에 내장되는 경우(이를 임베디드 시스템이라 하지요)라면 더더욱 그렇습니다.

일반적으로 뭔가 새 라이브러리나 실행 프로그램을 만들어야 한다면, 그래서 이를 위한 Makefile을 하나 작성해야 한다면, 기존에 존재하는 모듈들의 Makefile 중에서 내가 하려는 것에 가장 비슷한 걸 하나 복사한 다음, 최소한의 수정만 가해서 빌드하는 게 가장 빠르긴 합니다. 하지만 시간이 흐르면서, 모듈들이 많아지고, 요구 조건은 많이 변경됩니다. 하나 둘 컴파일 옵션 추가하는 일도 빈번해집니다. 그때마다 복사해서 사용하던 모든 Makefile들을 똑같이 고치는 단순 반복 노가다를 해야 합니다. 그중의 일부가 누락되면 컴파일 에러가 발생하거나, 운 나쁘면 런타임 에러가 발생합니다. 네, 소스 코드를 복사해서 사용하는 것과 똑같은, 아니 더 심각한 문제가 생기는 거죠.

좋은 환경이 주어지지 않은 걸 한탄만 한다고 달라지지는 건 없습니다. 뭔가 문제가 있다는 인식을 하고 그것을 꼭 해결하겠다는 의지만 있다면, 적어도 효율적인 소프트웨어 빌드 시스템은 만들어 낼 수 있습니다. 이 글은 그런 과정에서의 시행착오를 줄여서 생산적인 개발 작업에 좀더 집중할 수 있게 하고, 소프트웨어 개발자의 삶이 조금이나마 편해지는데 도움이 되었으면 하는 바람에서 쓰여 졌습니다.

사실 요즘은 좋은 빌드 툴들이 여럿 있습니다. 제 개인적으로는 jam 이나 waf 같은 것들을 고민해 봤던 경험이 있습니다. 특히 waf는 제가 좋아하는 python을 이용한 시스템이어서 참 매력적이었지만, 여러 명이 사용해야 하는 환경에서는, 관련된 사람들이 얼마나 쉽게 사용할 수 있어야 하느냐도 무척 중요합니다. 빌드 시스템을 관리하기 위해 새 언어를 배워야 한다라는 걸, 아주 바쁜(!) 여러 사람들한테 설득한다는 것은, 음… 쉽지 않은 일입니다.

그에 비해 Makefile을 작성해서 make로 빌드하는 건, 많은 개발자들, 특히 중요한 역할을 담당하는 경험 많은 개발자들일수록 익숙해져 있기 때문에, 빌드 시스템 구축 및 도입을 비교적 용이하게 할 수 있는 장점이 있습니다. 물론 make도 많은 기능을 가지고 있어서, 어느 정도 쓸 수 있기까지 시간과 노력이 좀 필요하지만, 일단 익숙해지고 나면 개발 과정에서 생기는 여러 가지 돌발 상황을 효과적으로 대응할 수 있습니다. 또한 개발을 진행하다 보면, 이런 저런 이유로 개발팀 외부의 소스 코드나 라이브러리를 활용해야 하는데, 많은 경우 Makefile이 제공되어 make를 이용해서 빌드하도록 되어 있기 때문에, 소프트웨어 개발자로 살아가는데 make를 잘 아는게 언젠가는 도움이 될 겁니다.

이제 그럼 make를 이용해서, “생산성과 품질을 중요시하는데 도움이 되는” 빌드 시스템을 실제로 만들어 보도록 하겠습니다.

 

반응형
반응형

아래 주소의 목록에서 더 많은 부분을 찾을 수 있다


http://msdn.microsoft.com/en-us/library/kk6xf663(v=vs.100).aspx


strcpy, wcscpy, _mbscpy

Visual Studio 2010
4 out of 4 rated this helpful Rate this topic

Copy a string. More secure versions of these functions are available; see strcpy_s, wcscpy_s, _mbscpy_s.

char *strcpy(
   char *strDestination,
   const char *strSource 
);
wchar_t *wcscpy(
   wchar_t *strDestination,
   const wchar_t *strSource 
);
unsigned char *_mbscpy(
   unsigned char *strDestination,
   const unsigned char *strSource 
);
template <size_t size>
char *strcpy(
   char (&strDestination)[size],
   const char *strSource 
); // C++ only
template <size_t size>
wchar_t *wcscpy(
   wchar_t (&strDestination)[size],
   const wchar_t *strSource 
); // C++ only
template <size_t size>
unsigned char *_mbscpy(
   unsigned char (&strDestination)[size],
   const unsigned char *strSource 
); // C++ only
strDestination

Destination string.

strSource

Null-terminated source string.

Each of these functions returns the destination string. No return value is reserved to indicate an error.

The strcpy function copies strSource, including the terminating null character, to the location specified by strDestination. The behavior of strcpy is undefined if the source and destination strings overlap.

Security noteSecurity Note

Because strcpy does not check for sufficient space in strDestination before copying strSource, it is a potential cause of buffer overruns. Consider using strcpy_s instead.

wcscpy and _mbscpy are wide-character and multibyte-character versions of strcpy. The arguments and return value ofwcscpy are wide-character strings; those of _mbscpy are multibyte-character strings. These three functions behave identically otherwise.

In C++, these functions have template overloads that invoke the newer, secure counterparts of these functions. For more information, see Secure Template Overloads.

Generic-Text Routine Mappings

TCHAR.H routine

_UNICODE & _MBCS not defined

_MBCS defined

_UNICODE defined

_tcscpy

strcpy

_mbscpy

wcscpy

Routine

Required header

strcpy

<string.h>

wcscpy

<string.h> or <wchar.h>

_mbscpy

<mbstring.h>

For additional compatibility information, see Compatibility in the Introduction.

// crt_strcpy.c
// compile with: /W3
// This program uses strcpy
// and strcat to build a phrase.

#include <string.h>
#include <stdio.h>

int main( void )
{
   char string[80];

   // Note that if you change the previous line to
   //   char string[20];
   // strcpy and strcat will happily overrun the string
   // buffer.  See the examples for strncpy and strncat
   // for safer string handling.

   strcpy( string, "Hello world from " ); // C4996
   // Note: strcpy is deprecated; consider using strcpy_s instead
   strcat( string, "strcpy " );           // C4996
   // Note: strcat is deprecated; consider using strcat_s instead
   strcat( string, "and " );              // C4996
   strcat( string, "strcat!" );           // C4996
   printf( "String = %s\n", string );
}
String = Hello world from strcpy and strcat!

반응형
반응형

http://www.cplusplus.com/reference/stl/






Not logged in
library

Containers

Standard Containers
A container is a holder object that stores a collection of other objects (its elements). They are implemented as class templates, which allows a great flexibility in the types supported as elements.

The container manages the storage space for its elements and provides member functions to access them, either directly or through iterators (reference objects with similar properties to pointers).

Containers replicate structures very commonly used in programming: dynamic arrays (vector), queues (queue), stacks (stack), heaps (priority_queue), linked lists (list), trees (set), associative arrays (map)...

Many containers have several member functions in common, and share functionalities. The decision of which type of container to use for a specific need does not generally depend only on the functionality offered by the container, but also on the efficiency of some of its members (complexity). This is especially true for sequence containers, which offer different trade-offs in complexity between inserting/removing elements and accessing them.

stackqueue and priority_queue are implemented as container adaptors. Container adaptors are not full container classes, but classes that provide a specific interface relying on an object of one of the container classes (such asdeque or list) to handle the elements. The underlying container is encapsulated in such a way that its elements are accessed by the members of the container class independently of the underlying container class used.

Container class templates

Sequence containers:

Container adaptors:

Associative containers:

Member map

This is a comparison chart with the different member functions present on each of the different containers:

Legend:
C++98Available since C++98
C++11New in C++11


Sequence containers

Headers<array><vector><deque><forward_list><list>
Membersarrayvectordequeforward_listlist
constructorimplicitvectordequeforward_listlist
destructorimplicit~vector~deque~forward_list~list
operator=implicitoperator=operator=operator=operator=
iteratorsbeginbeginbeginbeginbegin
before_begin
begin
endendendendendend
rbeginrbeginrbeginrbeginrbegin
rendrendrendrendrend
const iteratorsbegincbegincbegincbegincbegin
cbefore_begin
cbegin
cendcendcendcendcendcend
crbegincrbegincrbegincrbegincrbegin
crendcrendcrendcrendcrend
capacitysizesizesizesizesize
max_sizemax_sizemax_sizemax_sizemax_sizemax_size
emptyemptyemptyemptyemptyempty
resizeresizeresizeresizeresize
shrink_to_fitshrink_to_fitshrink_to_fit
capacitycapacity
reservereserve
element accessfrontfrontfrontfrontfrontfront
backbackbackbackback
operator[]operator[]operator[]operator[]
atatatat
modifiersassignassignassignassignassign
emplaceemplaceemplaceemplace_afteremplace
insertinsertinsertinsert_afterinsert
eraseeraseeraseerase_aftererase
emplace_backemplace_backemplace_backemplace_back
push_backpush_backpush_backpush_back
pop_backpop_backpop_backpop_back
emplace_frontemplace_frontemplace_frontemplace_front
push_frontpush_frontpush_frontpush_front
pop_frontpop_frontpop_frontpop_front
clearclearclearclearclear
swapswapswapswapswapswap
list operationssplicesplice_aftersplice
removeremoveremove
remove_ifremove_ifremove_if
uniqueuniqueunique
mergemergemerge
sortsortsort
reversereversereverse
observersget_allocatorget_allocatorget_allocatorget_allocatorget_allocator
datadatadata

Associative containers

Headers<set><map><unordered_set><unordered_map>
Memberssetmultisetmapmultimapunordered_setunordered_multisetunordered_mapunordered_multimap
constructorsetmultisetmapmultimapunordered_setunordered_multisetunordered_mapunordered_multimap
destructor~set~multiset~map~multimap~unordered_set~unordered_multiset~unordered_map~unordered_multimap
assignmentoperator=operator=operator=operator=operator=operator=operator=operator=
iteratorsbeginbeginbeginbeginbeginbeginbeginbeginbegin
endendendendendendendendend
rbeginrbeginrbeginrbeginrbegin
rendrendrendrendrend
const iteratorscbegincbegincbegincbegincbegincbegincbegincbegincbegin
cendcendcendcendcendcendcendcendcend
crbegincrbegincrbegincrbegincrbegin
crendcrendcrendcrendcrend
capacitysizesizesizesizesizesizesizesizesize
max_sizemax_sizemax_sizemax_sizemax_sizemax_sizemax_sizemax_sizemax_size
emptyemptyemptyemptyemptyemptyemptyemptyempty
reservereservereservereservereserve
element accessatatat
operator[]operator[]operator[]
modifiersemplaceemplaceemplaceemplaceemplaceemplaceemplaceemplaceemplace
emplace_hintemplace_hintemplace_hintemplace_hintemplace_hintemplace_hintemplace_hintemplace_hintemplace_hint
insertinsertinsertinsertinsertinsertinsertinsertinsert
eraseeraseeraseeraseeraseeraseeraseeraseerase
clearclearclearclearclearclearclearclearclear
swapswapswapswapswapswapswapswapswap
operationscountcountcountcountcountcountcountcountcount
findfindfindfindfindfindfindfindfind
equal_rangeequal_rangeequal_rangeequal_rangeequal_rangeequal_rangeequal_rangeequal_rangeequal_range
lower_boundlower_boundlower_boundlower_boundlower_bound
upper_boundupper_boundupper_boundupper_boundupper_bound
observersget_allocatorget_allocatorget_allocatorget_allocatorget_allocatorget_allocatorget_allocatorget_allocatorget_allocator
key_compkey_compkey_compkey_compkey_comp
value_compvalue_compvalue_compvalue_compvalue_comp
key_eqkey_eqkey_eqkey_eqkey_eq
hash_functionhash_functionhash_functionhash_functionhash_function
bucketsbucketbucketbucketbucketbucket
bucket_countbucket_countbucket_countbucket_countbucket_count
bucket_sizebucket_sizebucket_sizebucket_sizebucket_size
max_bucket_countmax_bucket_countmax_bucket_countmax_bucket_countmax_bucket_count
hash policyrehashrehashrehashrehashrehash
load_factorload_factorload_factorload_factorload_factor
max_load_factormax_load_factormax_load_factormax_load_factormax_load_factor

반응형
반응형

http://loki-lib.sourceforge.net/index.php?n=Main.Download



Download

Get the latest release from
 
Check out the most recent code, SVN howto at

Source code for "Modern C++ Design"

Download the source code of the book from:

Andrei's articles

Have a look at Andrei's articles.

반응형
반응형

http://www.swedishcoding.com/2008/08/31/are-we-out-of-memory/






Are we out of memory?

August 31st, 2008 by Christian Gyrling — Game Coding — 8 Comments

If I had a dollar every time I heard the question “Do we not have any more memory?”
When I ask the question “How much memory are you using for subsystem X?”, very few developers know the answer. It is usually a smaller or bigger ballpark but no definite answer.
Memory for any application is a crucial resource. No matter what type of application you are creating you will benefit from having good memory management. With some basic memory management in place you can know your memory distribution between systems, finding memory leaks much easier, simplify memory alignment requirements… These are just a few of the areas where you will benefit greatly with good memory management.

Getting the chaos under control

The first thing you need to do, unless you have already done it, is to override the global new and delete functions. Doing this gives you a starting point for all your memory management. All calls to new and delete will be handled by your custom functions. The very first step is to just intercept the allocation request and carry it out like it normal.

void* operator new(size_t size)
{
    return malloc(size, sizeof(char));
}

void delete (void* mem)
{
    free(mem);
}

// Don’t forget the array version of new/delete
void* operator new[](size_t size)
{
    return malloc(size, sizeof(char));
}

void delete[](void* mem)
{
    free(mem);
}

I’m not going to go into any detail about intercepting calls to malloc or the like. All I will say is that you will do best in staying away from using alloc, malloc, calloc, realloc and free (and all other permutations that I have forgotten). In most cases it can be tricky to intercept those calls. I would say that you should only use malloc once and that is to allocate all the needed memory for your application… but more about that later.

Custom versions of new and delete

You will quickly find that when you get an allocation request in you ‘new’ handler it would be very handy to know who made that allocation. From the code doing the allocation it would sometimes be very nice to be able to also specify extra information such as the alignment needed for the memory block. Aligned memory in particular is a pain to work with unless it is supported by the memory allocator. If you have a class that has members that need to be 16-byte aligned (SSE for example) it will be messy.

// Allocate memory with the needed padding to ensure that you
// can properly align it to the required boundary. Then you need
// to placement construct the new object in that memory.
char* pInstanceMem = new char[sizeof(MyClass) + 0x0F];
char* pAlignedMem = pInstanceMem & (~0x0F);
MyClass* pMyClassInst = new (pAlignedMem) MyClass();

// The allocation of the object it not terribly ugly but it is
// a pain to work with… but not as much of a pain as it is to
// delete the instance. The code below will crash or just leak.
// The destructor will be properly called but the memory address
// pointed to by pMyClassInst was never returned from a call
// to ‘new’. The memory address actually returned by the call
// to 'new' used for this object is really unknown at this point.
// What to do!?!?!?
delete pMyClassInst

Wouldn’t it be much nicer if you could allocate your MyClass instance like this…

// Just allocate with an extra argument to ‘new’
MyClass* pMyClassInst = new (Align(16)) MyClass();
MyClass* pMyClassInst = new (Align(16)) MyClass();

// and deletion will be straight forward… The pointer passed to
// ‘delete’ is the same pointer returned from the call to ‘new’.
delete pMyClassInst.

This is where overloaded versions of new and delete comes to the rescue.

// We use a class to represent the alignment to avoid any code
// situations where 'new (0x12345678) MyClass()' and
// 'new ((void*)0x12345678) Myclass()' might cause a placement
// construction instead of construction on an aligned memory
// address.
class Align
{
public:
    explicit Align(int value) : m_value(value)
    {
    }
    int GetValue() const
    {
       return m_value;
    }
private:
    int m_value;
};

// Overridden 'normal' new/delete
void* operator new (size_t size);
void* operator new[] (size_t size);
void operator delete( void* mem );
void operator delete[]( void* mem );

// Aligned versions of new/delete
void* operator new[] (size_t size, Align alignment);
void* operator new (size_t size, Align alignment);
void operator delete (void* mem, Align alignment);
void operator delete[] (void* mem, Align alignment);

Allocate all memory up front

Now when you have ways to allocate memory and pass arbitrary parameters to the allocator you can start organizing your memory.
If you need to ship an application that can only use 256 MB of RAM I would suggest that you allocate 256 MB of system memory up front and call that ‘retail memory’. Most of the time you need more memory during development of various systems and for this I would allocate another clump of memory… and call this memory ‘development memory’. You now have two huge buffers to use for your application and you should not allocate any more system memory. When you receive a call to ‘new’ you could check a variable whether to allocate the memory from the retail or the development memory pool.
By clearly separating the two memory pools you make sure that debug-only allocations end up in the debug pool and allocations needed to ship the game are taken from the retail pool. This way it is very clear from which pool you allocate memory and it is easy to keep track of the allocated/available memory. You could even use another custom overloaded new/delete that pass in whether the allocation should be from retail or development memory.

Divide and specialize

Now when you have your chunks of memory it might be a good idea to split it up based on the needs of your application. After all it’s terribly impractical to have only one huge buffer for an application. I am very much against dynamic allocations at run time of an application in general but some allocations have to happen and what is the best way of handling it?

A good way to organize the memory is to split the memory chunks into smaller blocks managed by different allocators using various allocation algorithms. This will not just help to be more efficient about the memory usage but will also serve as a way to clearly assign the memory to the various systems.

Not all allocations are the same. Here are a just few common allocations that came to mind.

PERSISTENT ALLOCATIONS

Allocated once at startup/creation of a system (pools, ring buffers, arrays). It will never be deleted and therefore we don’t need any complicated algorithms to allocate persistent memory. Linear allocations work great it this scenario. All it takes for an allocator like this is a pointer to the buffer, the size of the buffer and the current offset into the buffer (allocated space).

// Simple class to handle linear allocations
class LinearAllocator
{
public:
    LinearAllocator(char* pBuffer, int bufferSize) :
        m_pBuffer(pBuffer),
        m_buffersize(bufferSize),
        m_currentOffset(0)
    {
    }
    void* Alloc(size_t size)
    {
       void* pMemToReturn = m_pBuffer + m_currentOffset;
       pMemToReturn += size;
       return pMemToReturn;
    }
    void Free(void* pMem)
    {
       // We can't easily free memory in this type of allocator.
       // Therefore we just ignore this... or you could assert.
    }
private:
    char* m_pBuffer;
    int m_bufferSize;
    int m_currentOffset;
};

DYNAMIC ALLOCATIONS

This memory is allocated and freed at random points throughout the lifetime of the application. Sometimes you just need memory to create an instance of some object and you can’t predict when that will happen. This is when you can use a dynamic memory allocator. This allocator will have some type of algorithm to remember what memory blocks are free and which ones are allocated. It will handle consolidation of neighboring free blocks. It will however suffer from fragmentation which can greatly reduce the amount of memory available to you. There are tons of dynamic allocation algorithms out there, all with different characteristics; speed, overhead and more. Pick a simple one to start with… you can always change later.

ONE-FRAME ALLOCATIONS

These allocations happen for example when one system creates data and another consumes it later in that same frame. It could be variable sized arrays used for rendering, animation or just debug text created by some system earlier in the frame. This allocator handles this by resetting itself at the beginning (or end) of every frame, hence freeing all memory automatically. By doing this we also avoid fragmentation of the memory. The above LinearAllocator can be used here as well with the addition of a simple ‘Reset()’ function.

Memory Map

Conclusion

Well… I hope this is useful for someone out there. This type of information has helped me when I have worked on my personal or professional projects.

Another thing I did not talk much about is memory tracking. I guess all I will say about that for now is… Do it! Spend the time to implement something quick and easy to help you track down memory leaks and where in your code are you using up all the memory. This is a large topic by itself and therefore I will not write about it in this post. Make use of the overloading of the new/delete operators to allow you to pass __FILE__ and __LINE__ for each allocation. Use macros or other things to make the code prettier.

Until next time…

8 RESPONSES

  • Noel Llopis // Sep 2, 2008 at 5:51 am

    Very nice article, Christian. It’s very much how I like to deal with memory these days as well. I’m getting ready to write about memory allocation patterns for my column and this will definitely come in handy.

  • realtimecollisiondetection.net - the blog » Posts and links you should have read // Sep 2, 2008 at 7:34 am

    [...] a PC game developer). Learn the how’s and why’s by reading Christian Gyrling’s Are we out of memory? and Jesus de Santos Garcia’s post about Practical Efficient Memory Management (though the [...]

  • systematicgaming // Sep 3, 2008 at 10:54 pm

    This is a lot like my recent series on memory management – very similar ideas and implementations. That’s to be expected I suppose for similar applications (games) operating in similar environments.

  • James Bird // Sep 16, 2008 at 12:27 am

    I think there might be a bug in your alignment code.

    Assume that pInstanceMem = 3
    Then this would cause: pAlignedMem = 0

    Which is before the first byte of your allocated chunk of memory.

    I think what you meant to do was round up to the nearest multiple of 16, instead of down:

    pAlignedMem = (pInstanceMem + 0×0F) & ~(0×0F);

  • Christian Gyrling // Sep 16, 2008 at 9:46 am

    James… you’re right. Good catch. I did miss out on that when I wrote that example.
    I guess that will teach me to publish a post after midnight. :-)

  • Arseny Kapoulkine // Jan 3, 2009 at 2:23 am

    There is one minor problem with the code above – unless the code for delete(void*) and delete(void*, Align) is the same, it won’t work. delete ptr; always calls delete(void*), in fact the only case when delete(void*, Align) will be called is if ctor of the constructed class throws an exception.

  • Charles Nicholson // Jan 25, 2009 at 7:35 pm

    Hey Christian, Your “aligned delete” operator will only ever get called if the object being constructed throws when allocated with your “aligned new” operator.

    When you simply invoke ‘delete’ on a pointer that was allocated with your overloaded “aligned new”, your overloaded unaligned global operator delete will be called, not your “aligned delete” operator. See 5.3.4/17 and 5.3.4/19 for details.

    Or, run this code and see the compiler in action:

    #include
    #include

    enum MyToken
    {
    Charles
    };

    void* operator new(size_t size, MyToken token)
    {
    std::printf(“MyToken new\n”);
    return ::operator new(size);
    }

    void operator delete(void* p, MyToken token)
    {
    std::printf(“MyToken delete\n”);
    return ::operator delete(p);
    }

    struct Type
    {
    explicit Type(bool shouldThrow)
    {
    std::printf(“Type ctor\n”);
    if (shouldThrow)
    throw std::exception();
    }

    ~Type()
    {
    std::printf(“Type dtor\n”);
    }

    char c[256];
    };

    int main()
    {
    std::printf(“—New/delete without ctor-throw:\n”);
    delete new (Charles) Type(false);

    std::printf(“—New with ctor-throw:\n”);
    try
    {
    new (Charles) Type(true);
    }
    catch(const std::exception&)
    {
    }

    return 0;
    }

  • Jon B // Apr 14, 2010 at 7:18 am

    I think there may be a bug with your linear allocator…

    void* Alloc(size_t size)
    {
    void* pMemToReturn = m_pBuffer + m_currentOffset;
    pMemToReturn += size; // Oops..
    return pMemToReturn;
    }

    Should perhaps be…

    void* Alloc(size_t size)
    {
    void* pMemToReturn = m_pBuffer + m_currentOffset;
    m_currentOffset += size; // Thats better..
    return pMemToReturn;
    }

반응형
반응형

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html




gakushin logo

SFMT logo

SIMD-oriented Fast Mersenne Twister (SFMT):
twice faster than Mersenne Twister*1.

Japanese Version

News

LINK

What is SFMT?

SFMT is a new variant of Mersenne Twister (MT) introduced by Mutsuo Saito and Makoto Matsumoto in 2006. The algorithm was reported atMCQMC 2006. The article published in the proceedings of MCQMC2006. (see Prof. Matsumoto's Papers on random number generation.) SFMT is a Linear Feedbacked Shift Register (LFSR) generator that generates a 128-bit pseudorandom integer at one step. SFMT is designed with recent parallelism of modern CPUs, such as multi-stage pipelining and SIMD (e.g. 128-bit integer) instructions. It supports 32-bit and 64-bit integers, as well as double precision floating point as output.

SFMT is much faster than MT, in most platforms. Not only the speed, but also the dimensions of equidistributions at v-bit precision are improved. In addition, recovery from 0-excess initial state is much faster. See Master's Thesis of Mutsuo Saito for detail.

The following implementation SFMT19937 can be compiled in three possible platforms:

  1. Standard C without SIMD instructions
  2. CPUs with Intel's SSE2 instructions + C compiler which supports these feature
  3. CPUs with PowerPC's AltiVec instructions + C compiler which supports these feature

In each platform, SFMT has better performance than MT: see comparison of speed.

We put tables of equidistribution of SFMT. They are 32bit and 64bit.

Download SFMT which supports various periods from 2607-1 to 2216091-1

This code is released on January 31st in 2007, so it may contain some bugs. Any feedback is welcome (send an email to Mutsuo Saito, saito "at sign" math.sci.hiroshima-u.ac.jp and m-mat "at sign" math.sci.hiroshima-u.ac.jp)

versionarchivechanges
new!1.4SFMT-src-1.4.zip
SFMT-src-1.4.tar.gz
internal state of SFMT is kept in structure. function and macro names are changed to have sfmt_ prefix. This version can work with SFMT-jump. ALTIVEC OR BIGENDIAN ARE NOT TESTED AT ALL. (2012/6/28)
1.3.3SFMT-src-1.3.3.zip
SFMT-src-1.3.3.tar.gz
change not to compile do_recursion function when SSE2 or ALTIVEC is specified. This is to avoid compiler warning. (2007/10/6)
1.3.2SFMT-src-1.3.2.zip
SFMT-src-1.3.2.tar.gz
Fix bug about to_res53_mix() and genrand_res53_mix(). (2007/8/20)
1.3.1SFMT-src-1.3.1.zip
SFMT-src-1.3.1.tar.gz
Fix bug about compile error in MSC. Add two functions to_res53_mix() and genrand_res53_mix(). Change optimization option of gcc from -O9 to -O3. Add MSC __forceinline option. (2007/8/12)
1.3SFMT-src-1.3.zip
SFMT-src-1.3.tar.gz
Add support for the period 2216091-1. BUG fixed about BIG ENDIAN. Add parameter data for parallel generation. Support AltiVec on OSs which are not osx. (2007/6/2)
1.2SFMT-src-1.2.zip
SFMT-src-1.2.tar.gz
Now, various periods form 2607-1 to 2132049-1 are supported. The source code is combined. The second argument of vec_perm function is casted. (2007/3/1)
1.1sfmt19937src-1.1.zip
sfmt19937src-1.1.tar.gz
The period certification method is changed from constant to function. Makefile and documents changed. (2007/1/31)
1.0sfmt19937src-1.0.zip
sfmt19937src-1.0.tar.gz
First version.

If you have some trouble to download, try this page.

Double precision SIMD-oriented Fast Mersenne Twister (dSFMT)

The purpose of dSFMT is to speed up the generation by avoiding the expensive conversion of integer to double (floating point). dSFMT directly generates double precision floating point pseudorandom numbers which have the IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE Std 754-1985) format. dSFMT is only available on the CPUs which use IEEE 754 format double precision floating point numbers.

dSFMT doesn't support integer outputs. dSFMT supports the output of double precision floating point pseudorandom numbers which distribute in the range of [1, 2), [0, 1), (0, 1] and (0, 1). And it also supports the various periods form 2607-1 to 2132049-1. (dSFMT ver. 2.1 supports the periods from 2521-1 to 2216091-1.)

This code is released on March 12th in 2007, so it may contain some bugs. Any feedback is welcome (send an email to Mutsuo Saito, saito"at sign" math.sci.hiroshima-u.ac.jp and m-mat "at sign" math.sci.hiroshima-u.ac.jp)

The algorithm was reported at MCQMC 2008. This is the slide PDF file we used for the talk.
The article published in the proceedings of MCQMC2008. (see Prof. Matsumoto's Papers on random number generation.)

versionarchivechanges
new!2.2.1dSFMT-src-2.2.1.zip
dSFMT-src-2.2.1.tar.gz
Definitions of Shift constant in AltiVec were changed. They had not been fit to the instruction set architecture of AltiVec. (2013/2/21)
2.2dSFMT-src-2.2.zip
dSFMT-src-2.2.tar.gz
The initialization of the constants for sse2 is changed. dSFMT-common.h is created. This version can work with dSFMT Jump function. (2012/6/29)
2.1dSFMT-src-2.1.zip
dSFMT-src-2.1.tar.gz
This version supports the periods from 2521-1 to 2216091-1. We added new function dsfmt_genrand_uint32, which returns 32-bit unsigned integer. If you need many floating point pseudo random numbers and a few integers, you don't need to use another integer generator. (2009/4/18)
2.0dSFMT-src-2.0.zip
dSFMT-src-2.0.tar.gz
The recursion formula of dSFMT is changed. The supported periods are changed. The output sequences are completely changed. The generation speed is improved. The variable for initialization check is removed, because it causes an execution error in cygwin. dSFMT ver. 2.0 supports the periods from 2521-1 to 219937-1 currently. dSFMT ver. 2.0 is developed for higher speed. No serious problems are reported for dSFMT ver. 1.xx. (2008/8/26)
1.3dSFMT-src-1.3.zip
dSFMT-src-1.3.tar.gz
use structure of C language. bug fix about checking BIG_ENDIAN. Function names are changed to have the prefixdsfmt_, but old names are also available. (2008/2/28)
1.2.1dSFMT-src-1.2.1.zip
dSFMT-src-1.2.1.tar.gz
add #include <altivec.h> to dSFMT.c. (2007/8/29)
1.2dSFMT-src-1.2.zip
dSFMT-src-1.2.tar.gz
CAUTION: dSFMT.xxx.out.txt is changed. Bug fixed in test.c about printf precision specifier. Larger period 2216091-1 is supported. gcc compile option changed form -O9 to -O3. Add AltiVec parameter format for systems which are not OSX. Change Makefile for systems which are not OSX and support AltiVec. Change sample2 of howto-compile for Free BSD. Change period certification code more smart. Change source files for BORLANDC and Visual Studio. (2007/8/22)
1.1dSFMT-src-1.1.zip
dSFMT-src-1.1.tar.gz
Larger period 2132049-1 is supported. A bug about BIG ENDIAN machine is fixed. Some important bugs are fixed, but there is no influence to the outputs. Source codes were refactored. (2007/3/22)
1.0dSFMT-src-1.0.zip
dSFMT-src-1.0.tar.gz
The first version. (2007/3/12)

If you have some trouble to download, try this page.

CPUs and compilers for SFMT optimized for SIMD

SIMD typeCPUsgcc optiongcc version
SSE2Intel: Pentium M, Pentium 4, core, core 2, etc
AMD: Athlon 64, Sempron, Turion 64, etc
see Wikipedia SSE2:CPUs supporting SSE2
-msse23.4 or later
AltiVecPowerPC G4, G5-faltivec3.3 or later

See also How to compile SFMT.

License

SFMT, as well as MT, can be used freely for any purpose, including commercial use. See LICENSE.txt for detail.

.

Back to Mersenne Twister Home Page


*1 This work is supported in part by JSPS Core-to-Core Program No. 18005: "New Developments of Arithmetic Geometry, Motive, Galois Theory, and Their Practical Applications." 
This work is also partially supported by JSPS Grant-in-Aid for Scientific Research No. 16204002, No. 19204002 and No. 18654021.

반응형
반응형

http://www.microsoft.com/Korea/MSDN/MSDNMAG/ISSUES/2001/ctocsharp/default.aspx


C++ -> C#: C++에서 C#으로의 전환을 위해 알아 두어야 할 사항

Jesse Liberty
이 글을 이해하려면 C++에 대한 기본 지식이 있어야 합니다.
난이도? ?? 1?? 2?? 3?
요약 :C#는 C++의 구문과 의미를 바탕으로 설계되었으므로, C 프로그래머는 .NET 및 공용 언어 런타임을 충분히 활용할 수 있습니다. C++에서 C#으로의 전환은 비교적 쉬운 작업이지만, new, struct, 생성자 및 소멸자에 대한 변경 사항을 포함하여 몇 가지 유의해야 할 부분도 있습니다. 이 글에서는 가비지 수집, 속성, foreach 루프 및 인터페이스와 같은 C#에서 새로운 언어 기능을 살펴봅니다. 인터페이스를 다루면서 속성, 배열 및 기본 클래스 라이브러리도 함께 다룰 것입니다. 이어서, 비동기 I/O, 특성 및 검토, 형식 발견, 동적 호출 등에 대해 살펴봅니다.
거의 10년을 주기로 개발자들은 새로운 프로그래밍 기술을 익히기 위해 시간과 노력을 투자하고 있습니다. 1980년대 초에는 Unix와 C, 1990년대 초에는 Windows와 C++, 그리고 지금은 Microsoft .NET Framework와 C#이 대표적입니다. 이러한 과정이 진행되면서 들인 비용보다는 얻는 이익이 훨씬 더 많았습니다. 반가운 소식은 C#과 .NET으로 이루어지는 거의 모든 프로젝트의 분석 및 디자인 단계가 C++과 Windows의 방식에서도 바뀐 점이 별로 없다는 것입니다. 하지만 새로운 환경에서의 프로그래밍 접근 방식에는 상당한 차이가 있습니다. 이 글에서는 C++ 프로그래밍에서 C# 프로그래밍으로 전환할 수 있는 방법과 정보를 소개합니다.
 C# 구현의 향상 내용에 대해 소개한 자료는 많으므로 여기에서 다시 반복하지는 않겠습니다. 대신, C++과 C# 사이에 가장 많이 변경되었다고 생각되는 사항, 즉 관리가 없는 환경에서 관리 가능한 환경으로의 변화에 대해 집중적으로 살펴볼 것입니다. 또한 부주의한 C++ 프로그래머들이 주의해야 할 몇 가지 중요한 함정에 대해 소개하고, 프로그램 구현 방법에 영향을 미치는 새로운 언어 기능에 대해서도 살펴볼 것입니다.

맨 위로


관리 가능한 환경으로 이동

 C++은 플랫폼에 구애 받지 않는 하위 단계 수준 의 개체 지향형 프로그래밍 언어로 고안되었습니다. C#은 C++보다 상위 단계 수준 의 구성 요소 지향형 언어로 고안되었습니다. 관리 가능한 환경으로의 이동은 프로그래밍이라는 영역에서는 커다란 변화입니다. C#은 정확한 제어 보다는 전체적인 모습을 볼 수 있는 프레임워크를 제공합니다.
 예를 들어, C++의 경우 생성은 물론 개체의 레이아웃에 대해서도 많은 제어 권한을 가집니다. 즉 C++은 배치 연산자 new를 사용하여 개체를 다른 개체 스택 및 힙 위에 또는 메모리의 특정 위치에도 만들 수 있습니다.
 .NET의 관리 가능한 환경에서는 이러한 수준의 제어를 포기해야 합니다. 개체의 형식을 선택하면 해당 개체가 어디에 만들어지는지 암시적으로 정해집니다. 일부 형식(int, double 및 long)은 항상 스택(다른 개체 내부에 포함되는 경우 제외)에 만들어지고, 클래스는 항상 힙에 만들어집니다. 개체를 힙의 어디에 만들 것인지 제어할 수 없고, 해당 주소를 얻을 수 없으며, 특정 메모리 위치에 둘 수도 없습니다. 이러한 제약 사항을 해결할 수 있는 방법이 있기는 하지만 이 글의 주제에서 벗어나므로 생략하도록 합니다.
 이제는 더 이상 개체의 수명을 제어할 수 없습니다. C#에는 소멸자가 없습니다. 개체 저장 영역에 대한 참조가 더 이상 없을 경우에는 가비지 수집기가 해당 항목의 저장 영역을 회수할 것이지만, 그 시기에 대해서는 알 수 없습니다.
 C#의 구조를 통해 기본 프레임워크를 알 수 있습니다. 다중 상속은 관리되거나 가비지 수집이 이루어지는 환경에서는 효과적으로 구현하기가 매우 어렵고, 일반 사항은 프레임워크에서 구현되지 않았기 때문에 다중 상속과 템플릿이 없습니다.
 간단한 C# 형식은 하부 CLR(공용 언어 런타임) 형식에 대한 매핑에 불과합니다. 예를 들면, C# int는 System.Int32에 매핑됩니다. C#에서 형식은 언어가 아닌 공용 형식 시스템에 의해 결정됩니다. 사실, 사용자가 Visual Basic 개체에서 C# 개체를 만들어 내는 능력을 보유하려면 모든 .NET 언어에 의해 공유되는 기능인 공용 언어 하위 집합에 종속되어야 합니다.
 반면, 관리 가능한 환경 및 CLR를 통해 많은 이점을 얻을 수 있습니다. 가비지 수집 및 모든 .NET 언어에서의 단일 형식 시스템 이외에도, 크게 향상된 구성 요소 기반 언어를 얻게 됩니다. 구성 요소 기반 언어는 버전 관리를 완벽하게 지원하고 리플렉션를 통해 런타임에서 사용 가능한 확장가능 메타 데이터를 제공합니다. 후기 바인딩을 특별히 지원할 필요도 없습니다. 형식 찾기 및 후기 바인딩은 언어에 포함되어 있습니다. C#에서는 열거 및 속성이 언어의 첫 번째 클래스이고 이벤트 및 대리자(형식에 관계 없는 함수 포인터)와 마찬가지로 하부 엔진에 의해 완벽하게 지원됩니다.
 하지만 관리 가능한 환경의 최대 장점은 .NET Framework입니다. 프레임워크는 모든 .NET 언어에서 사용할 수 있고, C#은 프레임워크의 풍부한 클래스, 인터페이스 및 개체로 프로그래밍할 수 있도록 최적으로 고안된 언어입니다.

맨 위로


함정

 C#은 C++와 크게 달라 보이지 않기 때문에 전환이 쉬울 수 있지만, 여기에는 분명히 유의해야 할 함정이 있습니다. C++에서는 완벽하게 보이는 코드를 작성한 후 컴파일되지 않거나, 심한 경우 예상대로 작동하지 않을 수도 있습니다. C++에서 C#으로의 구문상 변화는 크지 않습니다. 다만 클래스 선언 뒤에 세미콜론이 없고, Main을 대문자로 시작한다는 정도입니다. 구문상의 변화를 쉽게 참고할 수 있도록 이러한 목록을 게시한 웹 페이지를 만들고 있지만, 컴파일러에서 쉽게 다룰 수 있으므로 여기에서는 다루지 않겠습니다. 그렇다고 해도 문제를 일으킬 수 있는 몇 가지 중요한 변화는 있음을 강조하고 싶습니다.

맨 위로


참조 및 값 형식
 C#에서는 값 형식과 참조 형식을 구분합니다. 단순 형식(int, long, double 등) 및 struct는 값 형식이고, 모든 클래스는 개체와 마찬가지로 참조 형식입니다. 값이 참조 형식 내부에 포함되지 않을 경우, 값 형식은 C++의 변수와 같이 스택에서 값을 가집니다. 참조 형식 변수는 스택에 있지만, C++의 포인터와 유사하게 힙에서 개체의 주소를 가집니다. 값 형식은 값(복사본)에 의해 메서드에 전달되는 반면, 참조 형식은 참조에 의해 효율적으로 전달됩니다.

맨 위로


Struct
 Struct는 C#에서 많이 다릅니다. C++의 경우 struct는 기본 상속 및 기본 액세스가 전용이 아닌 공용이라는 점만 제외하면 클래스와 동일합니다. 그러나 C#에서의 struct는 클래스와 매우 다릅니다. C#의 struct는 경량 개체를 캡슐화하기 위해 디자인되었습니다. 즉 struct는 참조 형식이 아닌 값 형식이므로 값에 의해 전달됩니다. 또한 클래스에 적용되지 않는 제한 사항이 있습니다. 예를 들어, struct는 봉인되어 있습니다, 즉 struct는 개체에서 파생되는 System.ValueType에서 파생될 수 없으며? 그것과 다른 기본 클래스를 가질 수도 없습니다. struct는 기본(parameterless) 생성자를 선언할 수 없습니다.
 반면, struct는 클래스보다 더욱 효율적이므로 경량 개체 생성에 가장 적합합니다. struct의 봉인 및 값 의미가 문제가 안 된다면 아주 작은 개체를 만들 때는 클래스보다 struct를 사용하는 것이 훨씬 유리합니다.

맨 위로


모든 것은 개체에서 파생
 C#의 경우 모든 것은 결국 개체에서 파생됩니다. 여기에는 생성 클래스는 물론 int 또는 struct와 같은 값 형식이 포함됩니다. 개체 클래스는 ToString과 같은 유용한 메서드를 제공합니다. 예를 들면, C#의 cout라 할 수 있는 System.Console.WriteLine 메서드인 ToString을 사용할 경우입니다. 이 메서드는 오버로드되어 개체의 문자열 및 배열을 가집니다.
 WriteLine을 사용하려면 기존 방식의 printf와는 달리 대체 매개 변수를 제공해야 합니다. myEmployee가 사용자 지정된 Employee 클래스의 인스턴스이고 myCounter가 사용자 지정된 Counter 클래스의 인스턴스라고 가정해 보겠습니다. 다음과 같은 코드를 작성할 수 있습니다.
Console.WriteLine("The employee: {0}, the counter value: {1}", myEmployee, myCounter);
WriteLine은 각 개체에 대해 가상 메서드인 Object.ToString을 호출하여 매개 변수 대신 반환된 문자열로 대체합니다. Employee 클래스가 ToString을 재정의하지 않을 경우, 기본 구현(System.Object에서 파생)이 호출되어 문자열로 클래스의 이름을 반환합니다. Counter는 ToString을 재정의하여 정수 값을 반환할 것입니다. 이 경우, 출력은 다음과 같습니다.
The employee: Employee, the counter value: 12
 정수 값을 WriteLine에 전달할 경우는 어떻게 될까요? 정수에 대해 ToString을 호출할 수는 없지만, 컴파일러는 값이 정수 값으로 설정될 개체의 인스턴스에서 int를 암시적으로 가둘 수 있습니다. WriteLine이 ToString을 호출할 경우 개체는 정수의 값을 나타내는 문자열을 반환합니다. (그림?1 참고)

맨 위로


Reference 매개 변수 및 Out 매개 변수
 C++과 마찬가지로 C#에서도 메서드는 하나의 반환 값만 가질 수 있습니다. C++의 경우 포인터 또는 참조를 매개 변수로 전달하여 이 제한 사항을 해결할 수 있었습니다. 호출된 메서드가 매개 변수를 변경하고, 호출하는 메서드는 다시 새로운 값을 사용할 수 있습니다.
 참조를 메서드에 전달하면 C++에서 참조 또는 포인터 전달을 통해 액세스하는 방식과 동일하게 원래 개체에 액세스할 수 있습니다. 하지만 이런 방식이 값 형식의 경우에는 해당되지 않습니다. 값 형식을 참조로 전달하려는 경우에는 값 형식 매개 변수를 ref 키워드로 표시해야 합니다.
public void GetStats(ref int age, ref int ID, ref int yearsServed)
ref 키워드는 메서드 선언과 메서드에 대한 실제 호출 모두의 경우에 사용해야 한다는 점을 유의하십시오.
Fred.GetStats(ref age, ref ID, ref yearsServed);
이제 호출 메서드에서 age, ID 및 yearsServed를 선언하고 GetStats로 전달하면 변경된 값을 얻게 됩니다.
 C#에서는 명확한 할당이 필요합니다. 즉 로컬 변수, age, ID 및 yearsServed는 GetStats를 호출하기 전에 초기화되어야 합니다. 이것은 불필요한 수고입니다. 이것들은 단지 GetStats에서 값을 얻기 위해서만 사용되기 때문입니다. 이 문제를 해결하기 위해 C#에서는 out 키워드도 제공합니다. 이 키워드는 초기화되지 않은 변수를 전달하고 참조에 의해 전달되도록 지정합니다. 다음은 이러한 의도를 명시적으로 나타내는 방법입니다.
public void GetStats(out int age, out int ID, out int yearsServed)
이 때, 호출 메서드는 일치해야 합니다.
Fred.GetStats(out age,out ID, out yearsServed);

맨 위로


New 호출
 C++의 경우, 키워드 new는 힙의 개체를 인스턴스화합니다. 하지만 C#의 경우는 그렇지 않습니다. 참조 형식의 경우, new 키워드는 힙의 개체를 인스턴스화합니다. 하지만 struct와 같은 값 형식의 경우 개체는 스택에서 생성되고 생성자가 호출됩니다.
 사실, new를 사용하지 않고 스택에 struct를 생성할 수도 있지만 조심해야 합니다. new는 개체를 초기화합니다. new를 사용하지 않을 경우 struct의 값을 사용하기 전에, 즉 메서드에 전달하기 전에 모든 값을 직접 초기화해야 하며, 그렇지 않을 경우 컴파일되지 않습니다. 또한 명확한 할당을 위해서는 모든 개체가 초기화되어야 합니다. (그림?2 참고)

맨 위로


속성
 대부분의 C++ 프로그래머는 멤버 변수를 전용으로 유지하려고 합니다. 이러한 데이터 숨김을 통해 캡슐화가 용이하고 클라이언트가 의존하는 인터페이스를 건드리지 않고도 클래스의 구현을 변경할 수 있기 때문입니다.그러나 클라이언트가 직접 이러한 멤버의 값을 얻거나 설정할 수 있게 하기 위하여, C++ 프로그래머는 전용 멤버 변수의 값을 수정하는 일을 담당하는 접근자 메서드를 생성합니다.
 C#에서 속성은 클래스의 첫 번째 클래스 멤버입니다. 클라이언트에게 속성은 멤버 변수로 보이지만, 클래스 구현자에게는 메서드로 보입니다. 이런 개념은 적절하다고 볼 수 있습니다. 즉 프로그래머는 완전한 캡슐화 및 데이터 숨김이 가능하고 클라이언트는 멤버에 쉽게 액세스할 수 있기 때문입니다.
 Employee 클래스에 Age 속성을 제공하여 클라이언트가 employee의 age 멤버를 얻고 설정하도록 할 수 있습니다.
public int Age { get { return age; } set { age = value; } }
 키워드 값은 속성에서 암시적으로 사용할 수 있습니다. 다음과 같이 작성하는 경우,
Fred.Age = 17;
컴파일러는 값으로 17을 전달합니다.
 Set 접근자가 아닌 Get 접근자를 사용하여 YearsServed에 대해 읽기 전용 속성을 만들 수도 있습니다.
public int YearsServed { get { return yearsServed; } }
이러한 접근자를 사용하기 위해 드라이버 프로그램을 변경할 경우 어떻게 작동하는지 볼 수 있습니다. (그림?3 참고)
 속성을 통해 Fred의 age를 얻은 다음, 이 속성을 사용하여 age를 설정할 수 있습니다. YearsServed 속성을 액세스하여 값을 얻을 수 있지만 설정할 수는 없습니다. 마지막 줄에서 주석을 제거하지 않을 경우 프로그램이 컴파일되지 않습니다.
 나중에 데이터베이스에서 Employee의 age를 가져오려는 경우 접근자 구현만 변경하면 됩니다. 클라이언트는 아무런 영향을 받지 않습니다.

맨 위로


배열
 C#에서는 기존의 C/C++ 배열보다 개선된 버전의 배열 클래스를 제공합니다. 예를 들어, C# 배열의 범위를 벗어나서 작성하는 것은 불가능합니다. 또한 Array에는 더 진보적인 기능의 ArrayList도 있습니다. ArrayList는 프로그램의 크기 변화에 대한 요구 사항을 동적으로 관리할 수 있습니다.
 C#에서 배열은 1차원, 다차원 사각형 배열(C++ 다차원 배열과 유사) 및 가변 배열(배열안의 배열)의 세 종류로 사용 가능합니다.
 1차원 배열은 다음과 같이 만들 수 있습니다.
int[] myIntArray = new int[5];
또는, 다음과 같이 초기화할 수도 있습니다.
int[] myIntArray = { 2, 4, 6, 8, 10 };
 다차원 사각형 배열은 다음과 같이 만들 수 있습니다.
int[,] myRectangularArray = new int[rows, columns];
또는, 다음과 같이 간단히 초기화할 수도 있습니다.
int[,] myRectangularArray = { {0,1,2}, {3,4,5}, {6,7,8}, {9,10,11} };
 가변 배열은 배열안의 배열이므로 1차원만 제공하면 됩니다.
int[][] myJaggedArray = new int[4][];
그런 다음, 다음과 같이 각 내부 배열을 만듭니다.
myJaggedArray[0] = new int[5]; myJaggedArray[1] = new int[2]; myJaggedArray[2] = new int[3]; myJaggedArray[3] = new int[5];
 배열은 System.Array 개체에서 파생되므로 Sort 및 Reverse를 포함하여 많은 수의 유용한 메서드와 함께 사용됩니다.

맨 위로


인덱서
 자신만의 배열 같은 개체를 만들 수도 있습니다. 예를 들면, 표시가 가능한 문자열 집합을 가진 목록 상자를 만들 수 있습니다. 배열에서 하듯이 인덱스로 상자의 내용을 액세스할 수 있다면 편리할 것입니다.
string theFirstString = myListBox[0]; string theLastString = myListBox[Length-1];
이것은 인덱서를 이용하면 가능합니다. 인덱서는 속성과 비슷한 점이 많지만, 인덱스 연산자의 구문을 지원합니다. 그림 4에서는 속성을 보여주는데 속성의 이름 다음에 인덱스 연산자가 옵니다.
 그림?5는 아주 간단한 ListBox 클래스를 구현하고 인덱스 기능을 제공하는 방법을 보여 줍니다.


맨 위로


인터페이스
 소프트웨어 인터페이스는 두 형식이 상호 작용하는 방식에 대한 계약입니다. 한 형식이 인터페이스를 등록하면 클라이언트에게 "다음 메서드, 속성, 이벤트 및 인덱서에 대한 지원을 약속한다"는 이야기를 하는 것입니다. 
 C#은 개체 지향형 언어이므로, 이러한 계약은 인터페이스라는 엔티티로 캡슐화됩니다. 인터페이스 키워드는 계약을 캡슐화하는 참조 형식을 선언합니다.
 개념적으로 보면, 인터페이스는 추상 클래스와 유사합니다. 차이가 있다면, 추상 클래스는 파생된 클래스의 패밀리에 대한 기본 클래스로 제공되고, 인터페이스는 다른 상속 트리와 혼합됩니다.


맨 위로


IEnumerable 인터페이스
 이전 예제로 다시 돌아가서, 일반 배열로 할 수 있는 것과 마찬가지로 foreach 루프를 사용하여 ListBoxTest 클래스에서 문자열을 출력할 수 있다면 좋을 것입니다. 이것은 클래스에서 IEnumerable 인터페이스를 구현해서 할 수 있고, IEnumerable 인터페이스는 다시 foreach 생성에 의해 암시적으로 사용됩니다. IEnumerable는 열거 및 foreach 루프를 지원하는 모든 클래스에서 구현됩니다.
 IEnumerable은 단 하나의 메서드인 GetEnumerator를 가지는데, 이 메서드의 임무는 IEnumerator의 특수한 구현을 반환하는 것입니다. 따라서, Enumerable 클래스의 의미를 통해 Enumerator를 제공할 수 있습니다.
 Enumerator는 IEnumerator 메서드를 구현해야 합니다. 이것은 컨테이너 클래스 또는 별도의 클래스에 의해 직접 구현할 수 있습니다. 이 중에서 두 번째 방식이 일반적으로 선호되는데, 그 이유는 컨테이너를 흩어 놓는 대신 Enumerator 클래스에서 해야 할 일을 캡슐화하기 때문입니다.
 이미 그림 5에서 보았던 ListBoxTest에 Enumerator를 추가할 것입니다. Enumerator 클래스는 컨테이너 클래스에만 해당되기 때문에(즉 ListBoxEnumerator는 ListBoxTest에 대해 많이 알고 있어야 하므로) ListBoxTest 내에 포함시켜 전용 구현으로 만들 것입니다.
 이러한 의미에서 ListBoxTest는 IEnumerable 인터페이스 구현을 위한 것으로 정의할 수 있습니다. IEnumerable 인터페이스는 Enumerator를 반환해야 합니다.
public IEnumerator GetEnumerator() { return (IEnumerator) new ListBoxEnumerator(this); }
메서드가 현재 ListBoxTest 개체(this)를 열거자에게 전달한다는 점을 알아두십시오. 이를 통해, 열거자가 이 특정 ListBoxTest 개체를 열거할 수 있게 됩니다.
 여기에서 Enumerator를 구현하기 위한 클래스는 ListBoxTest 내에서 정의된 전용 클래스인 ListBoxEnumerator로 구현되었습니다. 이 클래스의 임무는 매우 분명합니다.
 열거되는 ListBoxTest는 인수로 생상자에게 전달되고, 여기에서 멤버 변수인 myLBT에게 할당됩니다. 또한 생성자는 멤버 변수 인덱스를 -1로 설정하여 개체 나열이 아직 시작되지 않았음을 나타냅니다.
public ListBoxEnumerator(ListBoxTest theLB) { myLBT = theLB; index = -1; }
 MoveNext 메서드가 인덱스를 증가시킨 다음 열거하려는 개체의 마지막 부분을 넘어서 실행하지 않도록 확인합니다. 그럴 경우 false가 반환되고, 그렇지 않을 경우 true가 반환됩니다.
public bool MoveNext() { index++; if (index >= myLBT.myStrings.Length) return false; else return true; }
Reset은 인덱스를 -1로 재설정합니다.
 Current 속성은 마지막으로 추가된 문자열을 반환하기 위해 구현됩니다. 이것은 임의의 결정입니다. 다른 클래스에서 Current는 디자이너가 결정한 모든 해당 의미를 가지게 됩니다. 하지만 정의될 경우에는 현재 멤버에 대한 액세스는 열거자가 수행하는 임무이므로 모든 열거자가 현재 멤버를 반환할 수 있어야 합니다.
public object Current { get { return(myLBT[index]); } }
 이제 다 되었습니다. foreach에 대한 호출이 열거자를 페칭하고 이것을 사용하여 배열에 걸쳐 열거합니다. foreach는 의미 있는 값을 추가했는지 여부에 상관 없이 모든 문자열을 표시하므로, 관리하기 쉽게 표시 위해 myStrings의 초기화를 여덟 개의 항목으로 변경하였습니다.
myStrings = new String[8];

맨 위로


기본 클래스 라이브러리 사용
 C#이 C++과 어떻게 다르고, 문제 해결을 위한 접근 방식이 어떻게 바뀌어야 하는지에 대한 이해를 돕기 위해 다소 간단한 예제를 살펴보도록 하겠습니다. 큰 텍스트 파일을 읽고 화면에 해당 내용을 표시하는 클래스를 만들 것입니다. 이것을 다중 스레드 프로그램으로 만들어 데이터를 디스크에서 읽는 동안 다른 작업을 할 수 있도록 할 것입니다.
 C++에서는 파일을 읽는 스레드를 만들고, 다른 작업을 수행하는 스레드를 별도로 만들어야 합니다. 이러한 스레드는 독립적으로 작동하지만 동기화가 필요합니다. 이러한 모든 것을 C#에서도 할 수 있지만, 대부분의 경우 자신의 스레드를 작성할 필요는 없습니다. .NET에서 비동기 I/O를 위한 매우 강력한 메커니즘을 제공하기 때문입니다.
 비동기 I/O 지원은 CLR에 포함되어 있고 일반적인 I/O 스트림 클래스와 같이 사용이 쉽습니다. 컴파일러에게 많은 수의 System 네임스페이스에서 개체를 사용할 것임을 알리는 것부터 시작합니다.
using System; using System.IO; using System.Text;
System을 포함시켜도 그 밑의 모든 하위 네임스페이스가 자동으로 포함되지 않기 때문에 using 키워드를 사용하여 명시적으로 포함시켜야 합니다. I/O 스트림 클래스를 사용할 것이므로 System.IO가 필요하고, 바이트 스트림을 ASCII로 인코딩하기 위해서는 System.Text도 필요 합니다.
 이 프로그램 작성 단계는 매우 간단합니다. .NET이 대부분의 작업을 대신해 주기 때문입니다. Stream 클래스의 BeginRead 메서드를 사용할 것입니다. 이 메서드는 비동기 I/O를 제공하고, 버퍼에 가득 찬 데이터를 읽은 다음, 버퍼 프로세싱 준비가 되면 콜백 메서드를 호출합니다.
 콜백 메서드에 대한 버퍼 및 대리자로 바이트 배열을 전달해야 합니다. 이 두 가지를 드라이버 클래스의 전용 멤버 변수로 선언합니다.
public class AsynchIOTester { private Stream inputStream; private byte[] buffer; private AsyncCallback myCallBack;
멤버 변수 inputStream은 Stream 형식에 속하고 BeginRead 메서드를 호출하는 개체에 있으며, 대리자(myCallBack) 및 버퍼를 전달됩니다. 대리자는 멤버 함수에 대한 형식에 관계 없는 포인터와 매우 유사합니다. C#에서 대리자는 언어의 첫 번째 클래스 요소입니다.
 .NET은 바이트가 디스크의 파일에서 채워져 데이터를 처리할 수 있을 때 대리된 메서드를 호출합니다. 기다리는 동안 다른 작업을 수행할 수 있습니다. (이 경우 정수를 1에서 50,000으로 올릴 수 있지만, 생산 프로그램에서는 사용자와 상호 작용하거나 다른 유용한 작업을 수행할 수 있습니다.)
 .NET은 바이트가 디스크의 파일에서 채워져 데이터를 처리할 수 있을 때 대리된 메서드를 호출합니다. 기다리는 동안 다른 작업을 수행할 수 있습니다. (이 경우 정수를 1에서 50,000으로 올릴 수 있지만, 생산 프로그램에서는 사용자와 상호 작용하거나 다른 유용한 작업을 수행할 수 있습니다.)
public delegate void AsyncCallback (IAsyncResult ar);
 따라서, 이 대리자는 void를 반환하는 다른 모든 메서드와 연결될 수 있고 매개 변수로 IAsyncResult 인터페이스를 가집니다. CLR은 메서드가 호출되면 런타임에 IAsyncResult 인터페이스를 전달하므로, 다음과 같이 메서드만 선언하면 됩니다.
void OnCompletedRead(IAsyncResult asyncResult)
그런 다음, 생성자에서 대리자를 연결합니다.
AsynchIOTester() { ??? myCallBack = new AsyncCallback(this.OnCompletedRead); }
이것은 멤버 변수 myCallback(이전에 형식 AsyncCallback에 속하도록 정의)에게 대리자 인스턴스를 할당합니다. 대리자 인스턴스는 AsyncCallback 생성자를 호출하고 대리자와 연결하려는 메서드로 전달함 으로써 만들어집니다.
 다음은 전체 프로그램이 단계별로 작동하는 방식입니다. Main에서 클래스의 인스턴스를 만들고 실행되도록 합니다.
public static void Main() { AsynchIOTester theApp = new AsynchIOTester(); theApp.Run(); }
new에 대한 호출로 생성자가 실행됩니다. 생성자에서 파일을 열고 Stream 개체를 다시 얻습니다. 그런 다음, 버퍼에 공간을 할당하고 콜백 메커니즘을 연결합니다.
AsynchIOTester() { inputStream = File.OpenRead(@"C:\MSDN\fromCppToCS.txt"); buffer = new byte[BUFFER_SIZE]; myCallBack = new AsyncCallback(this.OnCompletedRead); }
Run 메서드에서 BeginRead를 호출하면 파일의 비동기적 읽기가 이루어집니다.
inputStream.BeginRead( buffer, // where to put the results 0, // offset buffer.Length, // how many bytes (BUFFER_SIZE) myCallBack, // call back delegate null); // local state object
이제 다른 작업으로 이동합니다.
for (long i = 0; i < 50000; i++) { if (i%1000 == 0) { Console.WriteLine("i: {0}", i); } }
읽기가 완료되면 CLR이 콜백 메서드를 호출합니다.
void OnCompletedRead(IAsyncResult asyncResult) {
OnCompletedRead에서 첫 번째로 해야 할 일은 Stream 개체의 EndRead 메서드를 호출하여 얼마나 많은 바이트가 읽혀졌는지 알아내고, 공용 언어 런타임에 의해 전달된 IAsyncResult 인터페이스 개체를 전달 하는 것입니다.
int bytesRead = inputStream.EndRead(asyncResult);
 EndRead 호출의 결과는 읽은 바이트의 수를 다시 받는 것이고. 수가 0보다 클 경우 버퍼를 문자열로 변환하여 콘솔에 쓴 다음, 다른 비동기 읽기를 유발하기위해 BeginRead를 다시 호출합니다.
if (bytesRead > 0) { String s = Encoding.ASCII.GetString(buffer, 0, bytesRead); Console.WriteLine(s); inputStream.BeginRead(buffer, 0, buffer.Length, myCallBack, null); }
이제 읽기가 진행되는 동안 다른 작업(이 경우는 50,000까지 카운트)을 수행할 수도 있지만, 버퍼가 가득 찰 때마다 읽은 데이터를 처리(이 경우는 콘솔에 출력)할 수 있습니다. 이 예제에 대한 전체 소스 코드 AsynchIO.cs는 이 글의 맨 위쪽에 있는 링크에서 다운로드할 수 있습니다.
 비동기 I/O의 관리는 전적으로 CLR에서 제공합니다. 네트워크에 대한 다음 내용을 읽어보면 이에 대한 장점을 더 많이 알게 될 것입니다.

맨 위로


네트워크를 통한 파일 읽기
 C++에서 네트워크를 통한 파일 읽기는 쉽지 않은 프로그래밍 작업입니다. .NET에서 이점을 폭넓게 지원합니다. 사실, 네트워크를 통한 파일 읽기는 표준 Base Class Library Stream 클래스 사용에 불과합니다.
 먼저, TCPListener 클래스의 인스턴스를 만들어 TCP/IP 포트(이 경우는 포트 65000)에서 수신하도록 합니다.
TCPListener tcpListener = new TCPListener(65000);
생성되었으면 TCPListener 개체가 수신을 시작하도록 합니다.
tcpListener.Start();
이제 클라이언트의 연결 요청을 기다립니다.
Socket socketForClient = tcpListener.Accept();
TCPListener 개체의 Accept 메서드는 Socket 개체를 반환하고, 이 개체는 표준 Berkeley 소켓 인터페이스를 나타내며 특정한 끝 지점(이 경우는 클라이언트)에 바인딩됩니다. Accept는 동기 메서드이고 연결 요청을 받을 때까지는 반환되지 않습니다. 소켓이 연결되면 클라이언트에게 파일을 보낼 준비가 마무리됩니다.
if (socketForClient.Connected) { ???
그 다음, NetworkStream 클래스를 만들어 소켓을 생성자에게 전달합니다.
NetworkStream networkStream = new NetworkStream(socketForClient);
그런 다음, 이전과 같이 StreamWriter 개체를 만들기는 하지만, 이번에는 파일이 아닌 방금 생성된 NetworkStream에서 만듭니다.
System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
이 스트림에 쓰면 스트림이 네트워크를 통해 클라이언트에게 전송됩니다. 전체 소스 코드 TCPServer.cs도 다운로드가 가능합니다.

맨 위로


클라이언트 생성
 클라이언트는 호스트에 TCP/IP 클라이언트 연결을 나타내는 TCPClient 클래스를 인스턴스화합니다.
TCPClient socketForServer; socketForServer = new TCPClient("localHost", 65000);
이 TCPClient로 NetworkStream을 만들고, 이 스트림에 대해 StreamReader를 만들 수 있습니다.
NetworkStream networkStream = socketForServer.GetStream(); System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
이제 스트림에 데이터가 있는 동안 계속 스트림을 읽고 결과를 콘솔에 출력합니다.
do { outputString = streamReader.ReadLine(); if( outputString != null ) { Console.WriteLine(outputString); } } while( outputString != null );
이것을 테스트하기 위해 간단한 테스트 파일을 만듭니다.
This is line one This is line two This is line three This is line four
다음은 서버에서의 출력입니다.
Output (Server) Client connected Sending This is line one Sending This is line two Sending This is line three Sending This is line four Disconnecting from client... Exiting...
다음은 클라이언트에서의 출력입니다.
This is line one This is line two This is line three This is line four

맨 위로


속성 및 메타데이터
 C#과 C++ 사이의 큰 차이점 중 하나는 C#에서는 메타데이터, 즉 클래스, 개체, 메서드 등에 대한 데이터를 기본적으로 지원한다는 것입니다. 특성은 CLR의 일부로 제공되는 특성과 자신의 필요에 맞게 만드는 특성, 두 종류가 있습니다. CLR 특성은 serialization, 마샬링 및 COM 상호 운용성을 지원하기 위해 사용됩니다. CLR을 검색해 보면 매우 많은 특성이 있다는 것을 알 수 있습니다. 이 중 일부 특성은 어셈블리에 적용되고, 다른 일부는 클래스 또는 인터페이스에 적용됩니다. 이러한 적용 대상을 특성 대상이라고 합니다.
 특성은 대상 항목 바로 앞에 두고 대괄호로 묶으면 해당 대상에 적용됩니다. 특성은 다음과 같이 다른 특성 위에 두거나,
[assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile(".\\keyFile.snk")]
여러 특성을 콤마로 구분함으로써 조합할 수도 있습니다.
[assembly: AssemblyDelaySign(false), assembly: AssemblyKeyFile(".\\keyFile.snk")]

맨 위로


사용자 지정 특성
 사용자 지정 특성을 자유롭게 만들고 적당한 때 런타임에 사용할 수 있습니다. 예를 들어, 코드의 섹션을 연결된 문서의 URL로 태그를 추가하는 문서 특성을 만들 수 있습니다. 또는, 코드를 코드 검토 주석이나 버그 수정 주석으로 태그를 추가할 수 있습니다.
 개발팀에서 버그 수정에 대한 기록을 유지하려는 경우를 생각해 보겠습니다. 모든 버그에 대한 데이터베이스를 유지하기 위해, 코드의 특정 수정 사항에 대해 버그 보고서를 연관시키려고 할 경우에는 코드에 다음과 같은 주석을 추가할 수 있을 것입니다.
// Bug 323 fixed by Jesse Liberty 1/1/2005.
 이렇게 해두면 소스 코드에서 쉽게 볼 수는 있겠지만, 이러한 정보를 보고서로 추출하거나 데이터베이스로 만들어 검색할 수 있도록 하면 더 좋을 것입니다. 또한 모든 버그 보고서 표시 방식을 동일한 구문으로 사용하면 좋을 것입니다. 이 때 필요한 것이 사용자 지정 특성입니다. 그러기 위해서는 주석을 다음과 같이 바꿀 수 있습니다.
[BugFix(323,"Jesse Liberty","1/1/2005") Comment="Off by one error"]
 특성도 C#의 클래스에 해당합니다. 사용자 지정 특성을 만들려면 System.Attribute에서 파생된 새로운 사용자 지정 특성을 만듭니다.
public class BugFixAttribute : System.Attribute
컴파일러에게 이 특성이 어떤 종류의 요소(특성 대상)와 함께 사용될 수 있는지 말해 주어야 합니다. 이것을 특성으로 지정합니다. (너무 당연한가요?)
[AttributeUsage(AttributeTargets.ClassMembers, AllowMultiple = true)]
AttributeUsage는 특성에 적용되는 특성(메타 특성)입니다. 이것은 메타 메타데이터, 즉 메타데이터에 대한 데이터를 제공합니다. 이 경우는 두 개의 인수를 전달하게 되는데, 하나는 대상(이 경우는 클래스 멤버)이고 다른 하나는 주어진 요소가 이러한 특성을 둘 이상 받을 수 있는지 여부를 나타내는 플래그입니다. AllowMultiple은 true로 설정되어 있는데, 이것은 클래스 멤버에 둘 이상의 BugFixAttribute가 지정될 수 있음을 의미합니다.
 Attribute 대상을 조합하려는 경우에는 OR를 사용할 수 있습니다.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true)]
이것은 특성이 Class 또는 Interface에 연결될 수 있도록 합니다.
 새로운 사용자 지정 특성의 이름은 BugFixAttribute입니다. 표기법은 단어 Attribute를 해당 특성 이름에 붙이는 것입니다. 특성을 요소에 지정하면, 컴파일러에서 특성을 짧은 버전의 이름으로 호출할 수 있도록 지원합니다. 따라서 다음과 같이 작성할 수 있습니다.
[BugFix(123, "Jesse Liberty", "01/01/05", Comment="Off by one")]
컴파일러는 먼저 BugFix라는 이름의 특성을 찾고, 이것을 찾지 못할 경우 BugFixAttribute를 찾습니다.
 모든 특성은 적어도 하나의 생성자를 가지고 있어야 합니다. 특성은 두 가지의 형식의 매개 변수를 가지는데, 하나는 위치 매개 변수이고 다른 하나는 이름 매개 변수입니다. 이전 예제에서 버그 ID, 프로그래머 이름 및 날짜는 위치 매개 변수이고, 주석은 이름 매개 변수에 해당합니다. 위치 매개 변수는 생성자를 통해 전달되고 생성자에서 선언된 순서대로 전달되어야 합니다.
public BugFixAttribute(int bugID, string programmer, string date) { this.bugID = bugID; this.programmer = programmer; this.date = date; }
이름 매개 변수는 속성과 같이 구현됩니다.

맨 위로


특성 사용
 특성을 테스트하기 위해 MyMath라는 이름의 간단한 클래스를 만들고 두 개의 함수를 부여합니다. 그런 다음, 클래스에 버그 수정 특성을 지정합니다.
[BugFixAttribute(121,"Jesse Liberty","01/03/05")] [BugFixAttribute(107,"Jesse Liberty","01/04/05", Comment="Fixed off by one errors")] public class MyMath
이러한 특성은 메타데이터와 함께 저장됩니다. 그림 6에 전체 소스 코드가 제공되어 있습니다. 다음은 출력입니다.
Calling DoFunc(7). Result: 9.3333333333333339
보는 바와 같이, 특성은 출력에 대해 전혀 영향을 미치지 않고, 특성을 만들어도 성능에는 아무런 영향이 없습니다. 사실, 특성이 존재한다는 사실도 제 말을 통해 믿을 수 밖에 없을 것입니다. 하지만 그림 7에서 보는 바와 같이 ILDASM을 사용한 메타데이터를 잠깐 살펴보면 특성이 있다는 사실을 알 수 있습니다.

맨 위로


검토
 검토가 유용하려면, 이상적으로는 런타임 동안 메타데이터에서 특성에 액세스하는 방법이 필요합니다. C#은 메타데이터 검사를 위한 검토를 지원합니다. 먼저 MemberInfo 형식의 개체를 초기화합니다. System.Reflection 네임스페이스의 이 개체는 멤버의 특성을 발견하고 메타데이터에 대한 액세스를 위해 제공합니다.
System.Reflection.MemberInfo inf = typeof(MyMath);
MyMath 형식에 대해 typeof 연산자를 호출합니다. 그러면 MemberInfo에서 파생된 형식 Type의 개체가 반환됩니다.
 다음 단계는 이 MemberInfo 개체에 대해 GetCustomAttributes를 호출하여 찾고자 하는 특성의 형식을 전달하는 것입니다. 이렇게 되면 개체 배열을 얻을 수 있으며, 여기서 이들 각 개체는 형식 BugFixAttribute에 속합니다.
object[] attributes; attributes = Attribute.GetCustomAttributes(inf, typeof(BugFixAttribute));
 이제 그림 8과 같이 이 배열에 걸쳐 반복하여 BugFixAttribute 개체의 속성을 출력할 수 있습니다. 이 대체 코드를 그림 6의 코드에 삽입하면 메타데이터가 표시됩니다.

맨 위로


형식 찾기
 검토를 사용하여 어셈블리의 내용을 찾고 검사할 수 있습니다. 어셈블리에 대한 정보를 표시할 도구를 만들거나 어셈블리에서 메서드를 동적으로 호출하려는 경우 특히 유용합니다. 스크립팅 엔진을 개발하여 사용자가 스크립트를 생성하고 프로그램을 통해 실행하도록 하려는 경우에도 해당합니다.
 검토를 통해, 모듈과 연관된 형식, 메서드, 필드, 속성 및 이벤트와 연관된 형식은 물론이고, 각 형식 메서드의 서명, 형식에 의해 지원되는 인터페이스 및 형식의 슈퍼클래스도 찾을 수 있습니다.
 우선, 어셈블리를 Assembly.Load 정적 메서드로 동적으로 로드합니다. 이 메서드에 대한 서명은 다음과 같습니다.
public static Assembly.Load(AssemblyName)
그런 다음, 코어 라이브러리를 전달해야 합니다.
Assembly a = Assembly.Load("Mscorlib.dll");
 어셈블리가 로드되었으면 GetTypes를 호출하여 Type 개체의 배열을 반환할 수 있습니다. Type 개체는 검토의 핵심입니다. Type은 형식 선언, 즉 클래스, 인터페이스, 배열, 값 및 열거를 나타냅니다.
Type[] types = a.GetTypes();
 어셈블리는 foreach 루프에 표시될 수 있는 형식의 배열을 반환합니다. 여기에서의 출력으로 많은 페이지가 채워집니다. 다음은 출력의 일부입니다.
Type is System.TypeCode Type is System.Security.Util.StringExpressionSet Type is System.Text.UTF7Encoding$Encoder Type is System.ArgIterator Type is System.Runtime.Remoting.JITLookupTable 1205 types found
코어 라이브러리의 형식으로 가득 찬 배열을 얻었고 이것을 하나씩 출력했습니다. 출력에서 보는 바와 같이 배열에는 1,205개 항목이 포함되어 있습니다.

맨 위로


형식에 대한 검토
 어셈블리의 단일 형식에 대해서도 검토할 수 있습니다. 이렇게 하려면, GetType 메서드로 어셈블리에서 한 형식을 추출합니다.
public class Tester { public static void Main() { // examine a single object Type theType = Type.GetType("System.Reflection.Assembly"); Console.WriteLine("\nSingle Type is {0}\n", theType); } }
출력은 다음과 같습니다.
Single Type is System.Reflection.Assembly

맨 위로


멤버 찾기
 그림 9에서 보는 바와 같이, 모든 해당 멤버에 대해 이 형식을 요청하여 모든 메서드, 속성 및 필드를 나열할 수 있습니다.
출력이 상당히 길어지긴 했지만 다음 출력의 일부에서 확인할 수 있듯이 출력 안에서 필드, 메서드, 생성자 및 속성을 볼 수 있습니다.
System.String s_localFilePrefix is a Field Boolean IsDefined(System.Type) is a Method Void .ctor() is a Constructor System.String CodeBase is a Property System.String CopiedCodeBase is a Property

맨 위로


메서드만 찾기
 필드, 속성 등은 제외하고 메서드에 대해서만 관심이 있을 수 있습니다. 이렇게 하려면, GetMembers에 대한 호출을 제거합니다.
MemberInfo[] mbrInfoArray = theType.GetMembers(BindingFlags.LookupAll);
그런 다음, GetMethods에 대한 호출을 추가합니다.
mbrInfoArray = theType.GetMethods();
이제 출력에는 메서드밖에 없습니다.
Output (excerpt) Boolean Equals(System.Object) is a Method System.String ToString() is a Method System.String CreateQualifiedName(System.String, System.String) is a Method System.Reflection.MethodInfo get_EntryPoint() is a Method

맨 위로


특정 멤버 찾기
 마지막으로, 더욱 범위를 좁히기 위해 FindMembers 메서드를 사용하여 형식의 특정 멤버를 찾을 수 있습니다. 예를 들어, 그림 10에서 보는 바와 같이 문자 "Get"으로 이름이 시작하는 메서드에 대한 검색으로 제한할 수 있습니다.
 출력의 일부는 다음과 같습니다.
System.Type[] GetTypes() is a Method System.Type[] GetExportedTypes() is a Method System.Type GetType(System.String, Boolean) is a Method System.Type GetType(System.String) is a Method System.Reflection.AssemblyName GetName(Boolean) is a Method System.Reflection.AssemblyName GetName() is a Method Int32 GetHashCode() is a Method System.Reflection.Assembly GetAssembly(System.Type) is a Method System.Type GetType(System.String, Boolean, Boolean) is a Method

맨 위로


동적 호출
 메서드를 찾았으면 검토를 사용하여 호출할 수 있습니다. 예를 들어, 각도의 코사인 값을 반환하는 System.Math의 Cos 메서드를 호출하려는 경우를 생각해 보겠습니다.
 이렇게 하려면, 다음과 같이 System.Math 클래스에 대한 Type 정보를 얻습니다.
Type theMathType = Type.GetType("System.Math");
 이 형식 정보로 해당 클래스의 인스턴스를 동적으로 로드할 수 있습니다.
Object theObj = Activator.CreateInstance(theMathType);
CreateInstance는 개체 인스턴스화를 위해 사용할 수 있는 Activator 클래스의 정적 메서드입니다.
 System.Math의 인스턴스가 있으면 Cos 메서드를 호출할 수 있습니다. 이렇게 하려면, 매개 변수의 형식을 설명하는 배열을 준비해야 합니다. Cos는 하나의 매개 변수(코사인 값이 필요한 각도)를 가지므로 하나의 멤버를 가진 배열이 필요합니다. 이 배열에 Cos에서 예상하는 매개 변수 형식인 System.Double 형식에 대한 Type 개체를 둡니다.
Type[] paramTypes = new Type[1]; paramTypes[0]= Type.GetType("System.Double");
 이제 원하는 메서드의 이름과 이전에 얻은 형식 개체의 GetMethod 메서드에게 매개 변수의 형식을 설명하는 이 배열을 전달할 수 있습니다.
MethodInfo CosineInfo = theMathType.GetMethod("Cos",paramTypes);
 이제 메서드를 호출할 수 있는 형식 MethodInfo의 개체를 가지고 있습니다. 메서드를 호출하려면, 배열에서 다시 매개 변수의 실제 값을 전달해야 합니다.
Object[] parameters = new Object[1]; parameters[0] = 45; Object returnVal = CosineInfo.Invoke(theObj,parameters);
 이제 두 개의 배열을 만들었습니다. 하나는 매개 변수의 형식을 가진 paramTypes이고, 다른 하나는 실제 값을 가진 매개 변수입니다. 메서드가 두 개의 인수를 가지고 있는 경우 이러한 배열이 두 값을 가지도록 선언하면 됩니다. 메서드가 값을 가지고 있지 않은 경우에도 배열을 만들 수 있지만, 크기를 0으로 부여해야 합니다.
Type[] paramTypes = new Type[0];
조금 이상하게 보이지만 이것이 맞습니다. 그림 11에 전체 코드가 나와 있습니다.

맨 위로


결론
 부주의한 C++ 프로그래머가 혼란스러워 할 수 있는 몇 가지 함정이 있기는 하지만 C#의 구문은 C++과 크게 다르지 않고 새로운 언어로의 전환은 비교적 쉽다고 볼 수 있습니다. C#으로 작업하면서 느끼는 흥미로운 점은, 이전에 직접 작성해야 했던 많은 기능을 제공하는 새로운 공용 언어 런타임 라이브러리를 항상 사용하게 된다는 점입니다. 이 글에서는 몇 가지 눈에 띄는 사항만 간단히 다루었습니다. CLR 및 .NET Framework는 스레드, 마샬링, 웹 응용 프로그램 개발, Windows 기반 응용 프로그램 개발 등을 위한 폭넓은 기능을 지원합니다.
 언어 기능과 CLR 기능간의 구분이 모호할 때가 많은 것이 사실이지만, 이 두 가지는 분명 강력한 개발 도구인 것입니다.

? 최종수정일: 2003년 1월 6일

반응형

'프로그래밍(Programming) > C#' 카테고리의 다른 글

C# 프로그래밍 가이드 - microsoft  (0) 2015.08.25
C# station 괜찮은 사이트  (0) 2013.06.07
C# 일관성 없는 액세스 가능성  (0) 2013.01.22
C#강의 51~55 끝  (0) 2012.10.31
c#강의 41~50  (0) 2012.10.31
반응형

http://icary.tistory.com/5



프로그램에서 편하게 Log를 남길 수 있는 class 입니다.

Singleton을 사용해서 multi thread 환경에서도 하나의 객체만 생성되며,

Log파일의 이름은 발생 날짜 정보와 실행파일의 이름을 조합하여 사용합니다.

Log는 argument list를 사용해서 printf에서 사용하는 다음의 format을 사용할 수 있습니다.
- %d : int
- %c : char
- %s : char *
더 많은 변수를 사용하려면 LogManager.cpp에서 다음 부분을 수정해서 사용하면 됩니다.
    va_start( argptr, mesg );
    for(int i = 0; i < format.GetLength(); i++){
        if(format.GetAt(i) != '%'){

   buffer2 = " ";
   buffer2.SetAt(0, format.GetAt(i));
            buffer += buffer2;
        } else {
            i++;
            switch(format.GetAt(i)){
                case 'd':
                    buffer2.Format("%d", va_arg(argptr,int) );
                    buffer += buffer2;
                    break;
                case 's':
                    buffer2.Format("%s", va_arg(argptr, char*) );
                    buffer += buffer2;
                    break;
                case 'c':
                    buffer2.Format("%c", va_arg(argptr, char) );
                    buffer += buffer2;
                    break;
            }
        }
    }
    va_end( argptr );

사용방법은 
1. LogManager.zip 을 다운 받는다.
2. LogManager.zip 의 압축을 푼다.
3. LogManager.h와 LogManager.cpp을 프로젝트에 추가한다.
4. 로그를 남기고 싶은 곳에서 
LogManager::GetInstance()->Log("Put your Log Here!!"); 
과 같은 방식으로 사용한다.

첨부파일

반응형
반응형

BLOG main image





결론적으론 둘다 결과는 139 가 된다


반복문 횟수가 많긴 하지만 시간에 있어서 약간 차이를 보인다



        timeTest1.startTime(); 


D3DXVECTOR3 vec1(3,-7,9);


float length=0;

for (int i=0;i<10000000;++i)

{

length=sqrtf(vec1.x*vec1.x+vec1.y*vec1.y+vec1.z*vec1.z);

length=length*length;

}


timeTest1.endTime();


timeTest2.startTime();

for (int i=0;i<10000000;++i)

{

length=vec1.x*vec1.x+vec1.y*vec1.y+vec1.z*vec1.z;

}

timeTest2.endTime();







이 정도 인데 sqrt는 특히나 매프레임마다 sqrt 를 호출하는 구조라면 상수들의 제곱으로써 피할 수 있는 방법은 없는지 생각해보는 것이 좋다



p.s 다른 수학함수도 내부적으로 좀 복잡해지는 것이라면 이와 마찬가지일지만서도 sqrt 는 좀 더 그러한듯..




반응형
반응형

♥ 에러 객체란?

" 에러객체 = 에러코드 + 에러문자열 "

프로그래밍을 하다보면 종종 에러코드를 정의해서 써야하는 경우가 있다. 종종이라기보다는 항상 에러코드를 정의해야한다. C++을 사용하는 나의 경우에는 enum을 주로 이용하여 에러코드가 겹치는 것을 방지하고, 다른 언어를 사용하는 사람들도 각자의 언어에서 제공하는 여러가지 방법을 사용하여 에러 코드를 정의해 쓸 것이다. 이렇게 에러코드들을 주루룩 정의해서 쓰다보면 한가지 아쉬운 점이 꼭 생각난다. 

"에러 코드만 넣으면 무슨 에러인지 알수 있는 방법은 없을까?"

오늘 소개해볼 '에러 객체'라는 것은 위의 불편함을 조금이라도 해결해 보기 위해 만들어진 몸부림 중에 하나다.

♥ 에러 객체에게 필요한 것들?

중복은 절대 안되!!
에러 코드는 중복되어서는 안된다. 한 가지의 에러를 나타내는데 하나의 코드만 쓰여야하고, 하나의 코드는 하나의 에러만을 가리켜야한다. 그래서 사람들은 enum 같은 곳에 에러 코드들을 정의함으로써 컴파일 타임에 자동적으로 중복되는 에러 코드를 피하려한다. 우리가 필요한 에러 객체에 중복된 코드가 있는 경우엔 컴파일 타임 에러가 발생할 수 있게 해야 한다.

코드만으로 무슨 에러인지 알고 싶어요!!
MS의 에러 코드를 생각 해 보라. 당최 알 수 없는 에러 코드가 떨어진다. 그 코드가 무엇인지 알기위해서는 MSDN을 뒤져 보거나 Error Lookup 툴을 이용하여야만 한다. 물론, 범용성을 제공하기 위해서는 정수형태의 에러코드 말고 다른 형태의 뭔가를 지원한다는 것이 상당히 어렵다. 하지만 나는 내 프로젝트에서 사용할 코드들을 정의하는 것이다. 문자열이 한글이든, 영어든 한가지만 선택하면 되는 것이고, 내가 알 수 있는 내용을 써 넣으면 된다.
지금 나에게 필요한 것은 범용성 보다는 별다른 툴 없이 바로 에러 문자열을 출력할 수 있는 방법이다.

에러 코드와 에러 문자열을 한자리에서 정의 하고 싶어요!!
만일 enum으로 에러 코드를 정의하고 문자열 배열로 에러 문자열들을 정의 하는 것도 괜찮은 방법이라 생각한다. 다만 에러 정의 들이 늘어나면 늘어 날 수록 유지 보수가 힘들어진다(진짜다 직접 해봐라!! 500개가 넘는 문자열 배열 과 에러코드를 동시에 관리하면 머리에 쥐난다).

♥ 어떻게 생겼을까?
위의 요구사항을 토대로 만들어진 코드를 살펴 보자. 장황한 서두와는 달리 실상 코드는 너무나도 간단하게 만들 수 있다.

에러 객체 기본 :
enum XXX_ERRORTYPE
{
     XXX_ERRORTYPE_SUCCESS, 
     XXX_ERRORTYPE_INFO,  
     XXX_ERRORTYPE_WARN,  
     XXX_ERRORTYPE_ERROR  
};

template <int TYPE, int SERVER, int ERRNO>  
struct XXX_ERROR {
     enum {
          ErrorCode = ((TYPE << 8 * 3) | (SERVER << 8 * 2) | ERRNO)
     };
     static const char* Desc; 
};

#define XXX_MAKE_ERRORCODE(name, type, server, errno, description) \
const char* XXX_ERROR<type, server, errno>::Desc = #description; \
typedef XXX_ERROR<type, server, errno> name;

// example
XXX_MAKE_ERRORCODE(XXX_ERROR_SOMEERROR,   TZ_ERRORTYPE_ERROR, 1,  1, "XXX 에러.")

그냥 ERROR이라고 하면 다른 뭔가와 충돌이 날것 같아 앞에 XXX를 붙였다. XXX에 큰 의미를 두지는 말자.

먼저 XXX_ERROR 객체를 살펴 보자. 
ErrorCode라는 enum을 선언하고 있다. ErrorCode는 값이 아닌 하나의 타입으로 인식되어 컴파일 타임에 결정 된다. TYPE, SERVER, ERRNO 같은게 나오고 이리 저리 시프트가 있어서 복잡해 보이기는 하지만 그것은 개인적으로 에러 코드를 카테고라이징하기 위해 사용하는 것이지 특별한 의미가 있는 것은 아니다. 필요 없다면 ERRNO 하나만으로 써도 무방하다. 

Desc는 description의 약자로 static const* 타입으로 선언되어 있다. 꼴에 문자열인지라 아무래도 컴파일 타임에 뭔가를 할 수 없어 대신 런타임에 아무도 내용을 바꾸지 못하도록 const를 사용했다.

XXX_MAKE_ERRORCODE 매크로로 눈을 돌려 보자. 이 매크로는 XXX_ERROR 템플릿 클래스를 찍어내는데 사용된다. 내부에는 static 변수의 초기화와 typedef 외에 다른 일은 하지 않는다. 하지만 한가지 기억할 것이 있다. 

"템플릿 클래스는 인자가 다른 경우 다른 타입으로 여겨진다."

위에서 type, server, errno에 다른 경우 동일한 템플릿 클래스로 만들고 있지만 항상 다른 타입으로 여겨진다는 것이다. 만일 위의 세 인자가 같은 경우(혹 하나로 해도 상관은 없다)라면 동일 타입의 static 변수를 두번 초기화하려 한다고 컴파일 에러가 발생한다. 만일 name이 같은 경우 역시 typedef를 두번 하려한다고 컴파일 에러를 발생 시킨다. 어쨋든 중복된 선언을 하게 된다면 컴파일이 안되게 만들었다는 말이다.

♥ 사용은 어떻게?
에러 객체라고 하지만 실상 아무런 객체도 생성되지 않는다. 그냥 타입의 enum 상수와 static 변수에 접근하는 것 뿐이다 :

if(XXX_ERROR_SOMEERROR::ErrorCode == SomeFunction())
{
     std::cout << XXX_ERROR_SOMEERROR::Desc << std::endl;
}

위에서 사용된 SomeFunction()은 에러 객체 템플릿 클래스에 대한 어떠한 정보도 없어도 된다. 단순히 정수형태의 에러 코드를 리턴하는 것이면 된다. 리턴하는 것은 에러 객체가 아닌 에러 객체에 정의된 enum을 리턴 한다.

문자열의 출력 역시, 에러 객체에 선언된 static 변수에 접근하여 초기화된 문자열을 출력하는 간단한 형태다. 

위와 같은 방식으로 에러 정보를 관리하게 되면 에러 코드 넘버와 에러문자열을 항상 한쌍으로 관리 할 수 있으므로 관리에 용이성과, 컴파일 타임에 중복 체크를 보장 받을 수 있다.

다만 단점으로는 static 변수들의 무수한 생성과 enum 처럼 자동으로 에러 코드를 증가 시켜주는 도구가 없다는 불편함이 있다.



참조 :
 - Modern C++ Design - 안드레 알렉산드레쿠스
 - [진리는어디에] - 템플릿 특화를 이용한 튜플 클래스
 - [진리는어디에] - 템플릿 특화(Template specialize)
 - [진리는어디에] - 템플릿 특화를 이용한 멀티 키 맵(Multi Key Map)

반응형
반응형
아래 포스트한 내용처럼 pack 을 사용하기도 하지만 멤버변수 선언 순서를 잘 맞춰 선언하는 것이 효율적이다







http://pdw1208.tistory.com/entry/pragma-pack


#include <stdio.h>

struct test{
  int iNum;
  char A;
  short B;
  char C;
};

void main()
{
  struct test B;
  
  B.iNum = 1000;
  printf("구조체의 크기는 %d\n"sizeof(B));
  
}















구조체의 크기가 12라고 출력이 되었다  좀 이상하다 


int  +  char + short + char 는 즉
 4   +    1    +   2    +   1  =  8 이 나와야 정상이다 

32비트 CPU는 4바이트 최적화를 한다 다음으로는 2바이트 최적화를 한다

따라서 그림과 같이 메모리에 들어가지 않고  




아래 그림과 같이 들어간다 A다음에 3바이트가 남아서 이럴경우는 다시 2바이트 최적화를 한다 

4바이트 메모리구조에서 메모리상에서 2바이트 최적화의 경우는 앞에 2바이트 뒤에 2바이트로 최적화를 하지

위 그림에서 B와 같이 중간에 2바이트를 할당하지 않는다 아래 그림과 같이 뒤에 2바이트를 할당한다 

남은 C 즉 1바이트는 B 다음에 할당한다 그래서 구조체의 크기는 12가 나오는 것이다     

A와 B 사이의 1바이트는 죽은 공간으로 사용은 하지 않지만 메모리만 잡아먹는 죽은 공간이다 




이를 해결하는 방법이 #pragma pack 을 이용해 메모리를 1바이트 최적화를 해주는 것이다 

#include
 <stdio.h>

#pragma pack(push, 1)  // (1) 이렇게도 사용가능 
struct test{
  int iNum;
  char A;
  short B;
  char C;
};
#pragma pack(pop)  // (4)  이렇게도 사용가능 

void main()
{
  int A = 100;
  struct test B;

  B.iNum = 1000;

  printf("구조체의 크기는 %d\n"sizeof(B));
}
 



구조체 전에 

#pragma pack(push, 1) 이나 (1) 을 선언해 메모리를 1바이트 최적화를 시킨다 그렇게되

면 구조체의 크기는 선언된 변수의 자료형의 크기만큼의 구조체를 가진다 

구조체선언 다음에  #pragma pack(pop) 이나 (4) 선언해 다시 4바이트 최적화를 해준다  

32비트 CPU에서는 4바이트(32비트)의 단위로 데이터를 처리하는 것이 가장 빠르게 때문이다  즉 

#pragma pack(1) 또는 (push ,1) 이라고 선언해놓고 원래대로 돌려놓지 않는다면 속도저하의 문제가 생

길 수 있다


각변수는 메모리상에서 그림과 같이 공간을 차지한다   
 

반응형
반응형


마지막 128 전까지는 vc 어떤 버전이든 고정된 바이트를 제공한다


마지막 __m128은 부동소수 4개를 합쳐놓은 타입으로 SIMD 방식으로 벡터곱생등을 수행할 때 사용될 수 있다



std::cout<<sizeof(__int8)<<std::endl;

std::cout<<sizeof(__int16)<<std::endl;

std::cout<<sizeof(__int32)<<std::endl;

std::cout<<sizeof(__int64)<<std::endl;

std::cout<<sizeof(__m128)<<std::endl;






BLOG main image

반응형
반응형

http://cafe.naver.com/apollocation/479

 

 

별거아니지만 혹시나 필요하신분들이 있을까봐 올립니다~

 

 

3dmax에서 작업후 Collada(dae)파일로 export하여 papervision3d에서 사용하는 방법인데요.

 

필요하신분들은 유용하게 쓰시길 바래요~ㅋ

 

일단 collada란 플러그인이 필요한데,

 

http://update.multiverse.net/wiki/index.php/Installing_the_3ds_Max_COLLADA_Plugin

이곳으로 가시면 됩니다.

 

위치는 아래그림에 있답니다~

 





 

 

collada plugin파일을 다운받으셨으면 다음과 같은 경로에 넣습니다~

 

 

 

3dmax가 설치되어있는경로에 plugins란 폴더에 넣으시면 되겠죠.

 

 

그다음,

 

더블클릭~하시면..

 

 

[Next]하시고

 

[I Agree]하시고나면

 

 

이와같은 창이 뜹니다.

 

저는 3ds Max 9.0을 쓰기때문에..

 

 

 

이와같이 체크를 풀어주고

 

[Next] 클릭.!

 

그다음 [Install] 클릭하시면 되요~

 

 

 

아주 잘 되고 있습니다~ㅋ

 

다되면 [Finish] !!

 

 

아까 설치한 경로를 다시 들여다보면

 

ColladaMax.dle란 파일이 생겼죠?

 

저것이 플러그인이란 놈인가 봅니다.

 

그다음 3dMax를 실행해서 직접 Export를 해봐야겠죠.

 

 

 

저는 간단하게 박스를 만들어 봤습니다~

 

Max를 잘하시는 분들은 멋있는걸 만드시겠죠~ㅎㅎ

 

그다음 [File]-[Export] 또는,

          [File]-[Export Selected]를 클릭합니다.

 

 

파일형식을 보다보면 COLLADA(*.DAE)란 놈이 있죠.

 

우리는 저놈으로 Export를 해야합니다~

 

클릭!

 

파일 이름을 입력하시고 저장 하시면!

 

 

이러한 창이 뜨네요.

 

뭐 그냥 이것저것 속성을 보여주는 창 같은데.

 

저는 잘 모르겠네요~그냥 OK버튼 눌러서 하면 멀쩡히 잘 돌아가니까 "OK"합니다~

 

추후에 저거에 대하여 잘 알고계신분들은 글 하나 남겨주시면 정말 감사하겠습니다~

 

그다음 export되어있는 경로를 가보면

 

[파일이름].DAE파일이 생성되어있는걸 보실수 있습니다.

 

정말 간단하죠?

 

필자는 이 파일을 Papervision3d에서 돌리는 작업을 하고 있습니다.

 

MAX파일이 복잡해지면 용량이 커지면서 꽤 느리더군요..

 

공부를 더 많이 해봐야될것 같습니다.

 

처음으로 이런 자료를 올린거라 많이 허접하고 부족하네요;

 

그래도 하루종일 여기저기 물어보고 찾아보고 삽질하며 찾아본 자료랍니다~

 

다음엔 더 유용한 자료를 올릴수 있도록..^^;

 

좋은하루 되시길~

 

 

반응형
반응형


http://warmz.tistory.com/872


CView 클래스에서 WM_SETCURSOR 메시지를 추가하고 아래와 같이 사용한다.

선언

1
2
3
4
5
6
7
8
9
10
11
12
13
// Cursor Style for Shape control
enum CursorStyle {
    CursorArrow = 0,
    CursorCross,
    CursorInputText,
    CursorSizeAll,
    CursorSizeNESW,     // 우측상단에서 좌측하단
    CursorSizeNS,       // 수직
    CursorSizeNWSE,     // 좌측상단에서 우측하단
    CursorSizeWE        // 수평
};
 
HCURSOR m_CursorStyleList[8];

아이콘 할당

1
2
3
4
5
6
7
8
9
10
11
CTestView::CTestView()
{
    m_CursorStyleList[CursorArrow] = LoadCursor(NULL, IDC_ARROW);
    m_CursorStyleList[CursorCross] = LoadCursor(NULL, IDC_CROSS);
    m_CursorStyleList[CursorInputText] = LoadCursor(NULL, IDC_IBEAM);
    m_CursorStyleList[CursorSizeAll] = LoadCursor(NULL, IDC_SIZEALL);
    m_CursorStyleList[CursorSizeNESW] = LoadCursor(NULL, IDC_SIZENESW);
    m_CursorStyleList[CursorSizeNS] = LoadCursor(NULL, IDC_SIZENS);
    m_CursorStyleList[CursorSizeNWSE] = LoadCursor(NULL, IDC_SIZENWSE);
    m_CursorStyleList[CursorSizeWE] = LoadCursor(NULL, IDC_SIZEWE);
}

아이콘 지정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BOOL CDrawingToolView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    CPoint pt;
     
    GetCursorPos(&pt);
    ScreenToClient(&pt);
 
    if(m_rect.PtInRect(pt))
    {
        SetCursor(m_CursorStyleList[CursorSizeAll]);
    }
    else
    {
        return __super::OnSetCursor(pWnd, nHitTest, message);
    }
 
    return TRUE;
}
 


아이콘의 종류




*손모양은 IDC_HAND

반응형

+ Recent posts