비공개2011. 10. 13. 15:02


툴 릴리즈 버전을 배포하다보면 간혹 다음과 같은 상황이 발생!

내 자리에서는 잘 되는데 다른 사람 컴퓨터에서는 실행이 제대로 안된다. ( 개발자들이 자주하는 불편한 진실 -_-;;; )

여러 상황이 있지만 " xxxx.dll 이 없습니다. "  라 메세지 뜨고 실행이 안된다.

프로젝트에 실행함에 있어서 관련된 라이브러리는 동적이 아닌 정적으로 연결시켜주자.

그래야 그나마 어느 컴퓨터에서 별 무리없이 잘 사용되는 범용적인 툴이된다.


속성 -> 구성 속성 -> 일반 -> MFC 사용 > 정적 라이브러리에서 MFC 사용 (select)
속성 -> 구성 속성 -> 일반 -> ATL 사용 > ATL에 정적 링크(select)

속성 -> 구성 속성 -> C/C++ -> 코드 생성 -> 런타임 라이브러리 -> 다중 스레드(/MT) ( select ) // Release 용

( Debug 모드에서 /MT를 사용할 경우 'error LNK2001: __CrtDbgReport' 에러가 발생할 수 있다 )

속성 -> 구성 속성 -> C/C++ -> 코드 생성 -> 런타임 라이브러리 -> 다중 스레드(/MTd) ( select ) // Debug 용

 

 

Posted by 닭꽝
비공개2011. 9. 22. 10:44


※ 자신이 만든 클래스에서 다른 자료형과 호환되게 하기에 유용!

operator
 변환타입()

{

          /* code */ 

          return 변환타입;

}

예시) 

D3DXCOLOR -> DWORD 변환
 

D3DXCOLOR foo( 255.f, 123.f, 456.f, 255.f );

DWORD color = foo;


 
<d3dx9math.h>

typedef struct D3DXCOLOR


     ...
     
// casting
    

operator DWORD () const; 
     ... 

}

<dxdx9math.inl>

D3DXINLINE

D3DXCOLOR::operator DWORD () const

{

    DWORD dwR = r >= 1.0f ? 0xff : r <= 0.0f ? 0x00 : (DWORD) (r * 255.0f + 0.5f);

    DWORD dwG = g >= 1.0f ? 0xff : g <= 0.0f ? 0x00 : (DWORD) (g * 255.0f + 0.5f);

    DWORD dwB = b >= 1.0f ? 0xff : b <= 0.0f ? 0x00 : (DWORD) (b * 255.0f + 0.5f);

    DWORD dwA = a >= 1.0f ? 0xff : a <= 0.0f ? 0x00 : (DWORD) (a * 255.0f + 0.5f);


    return (dwA << 24) | (dwR << 16) | (dwG << 8) | dwB;

}

 

'비공개' 카테고리의 다른 글

log 파일 실시간 검사 Utility  (0) 2011.11.30
Tool 배포시 유의점  (0) 2011.10.13
Direct3D Device Lost  (0) 2011.09.09
memset 무심결에 잘 모르고 썻던 부분  (0) 2011.08.16
UNICODE와 MBCS 호환성 및 사용법  (0) 2011.08.11
Posted by 닭꽝
비공개2011. 9. 9. 10:38

Direct를 사용하면서 Device Lost 발생시 관련 문제사항을 경험 위주로 이 문서에 정리해야겠다.

 



상황1. 게임 해상도 변경시 Device Lost가 발생한다. 그리고 복구 처리되도록 설계가 되어있다.
             그러나 어느날 갑자기 다음 함수가 실패 하는 것!

             증상은 이 후 Present(...) 함수도 실패 처리됨. Clear(...) 호출 이후 화면갱신이 이루어지지 않음.


 
1
m_pd3dDevice->Reset( &m_d3dpp ); //  D3DERR_INVALIDCALL 발생


찾아보니 Reset() 함수 호출 전에 생성된 텍스쳐를 모두 Release 해줘야 한다는 것!
( 물론, 개고생해서 찾음 ㅜ.ㅡ )


갑자기 발생한데는 이유가 있다. 근간에 내가 작성한 코드가 문제가 되는것!!

D3DXCreateTexture( ... )로 생성한 텍스쳐와 ID3DXLine가 해상도 변경전(Reset()호출전)에 Release 되지 않았던 것!


해결1. Reset() 호출전에 텍스쳐 삭제 및 ID3DXLine을 맴버로 둔 클래스를 삭제(delete) 후
             Device 복구 시 재생성(new) 처리






Posted by 닭꽝
비공개2011. 8. 16. 11:08

함수원형은 대략 이렇다.

void* memset( void* data, int val, int size );

사용하는 대부분의 경우가 나도 특정 데이터를 0이나 1로 초기화 할 때에만 사용해왔었다.

그냥 그대로 0과 -1로 초기화 할때에만 사용하자. ㅎㅎ

아님 클란다. ㅋㅋ

 

 


요점은 memset의 경우 void* 로 넘긴 데이터에 val 값을 size만큼 byte 단위로 채운다는 점이다.

int의 경우 4byte가 유효한 하나의 값인데 byte 단위로 1이 들어가 있다면 위와같은 꼴난다. ㄷㄷ

아참! 위에 선언한 배열이 char 형이라면 제약이 거의(?) 없다.
그외에 int형이나 Class 및 sturcture 등을 memset 함수에 사용 할 경우를 말한다!
Posted by 닭꽝
비공개2011. 8. 11. 09:47
현업에서 일하다보면 문자열을 다양하게 주물러야 할 때가 많다.
현재도, EXECL에 저장되어 있는 태국어를 내가 만든 툴에서 가져와 저장할 때 데이터가 깨지는 현상이 발생하였다.

뭐, Tool 자체적으로는 다른나라 신경안쓰고 만들었지만 앞으로 태국, 중국, 대만, 일본 등 다양한 나라에서도 이 Tool을
사용해야하는데 이참에 다국어를 어느정도(?) 지원하게끔 만들려고 한다.

가장 먼저 부딛히는 것이... 

1
2
CString     rtnStr = vt.bstrVal;   // Success! BSTR 타입.
std::string rtnStr = vt.bstrVal;   // Error!

이처럼 같은 문자열을 처리하도록 만든 클래스가 서로 다르게 동작한다. 진작 이점은 알고 있었고 주어들은것도 있지만
여지껏 기본동작만을 사용하기에 별문제가 없어 그냥 대충 암거나 사용했던것이 기억이 난다.

허나, 조금더 복잡하고 다양한 기능을 제공하기 위해서는 속도, 안정성, 유지보수 등이 도마위에 오르기 때문에 내가 지금 사용하고 있는 것들의 사용법 혹은 개념들을 정확히 알고 있어야 한다. 그렇지 않으면 매번 같은 문제로 골머리 썩는 좀비 프로그래머가 되는 것이다. 생각 또 생각을 달고 살아야하는게 프로그래머의 길! 이 아닐까 싶다. 치매는 안걸릴듯 ㅋㅋ


CString 과 std::string의 차이점은 뭔가? 

-  std::string은 말그대로 표준 템플릿 라이브러리이다. UNICODE 사용은 std::wstring 형태로 지원한다.
   사용을 위해서는 #include <iostream> 가 필요하다.

-  CString은 마이크로소프트에서 제작 및 배포하는 템플릿 라이브러리로 동일 이름으로 UNICODE를 지원한다.
    MFC 프로젝트를 생성하면 기본적으로 포함되어 사용이 가능하나 아니라면 atlstr.h 를 포함시켜줘야
    사용가능하다.

■ 유니코드(UNICODE)와 멀티바이트(MBCS)를 동시에 다루는 프로젝트 내에서의 대응?

- MBCS와 UNICODE 상호호환 되는 코드를 작성하자.
  여기서 말하는 호환은 문자열을 런타임단계에서 서로 인식하는것을 말하는 것이 아니라
  프로젝트 속성에서 UNICODE 와 MBCS 사용을 변경하여도 문제가 발생하지 않고 제대로 동작하는 것을 말한다.


먼저, 멀티바이트(MBCS) 와 유니코드(UNICODE)의 관계를 알아보자.
각각의 기본개념은 http://blog.daum.net/coolprogramming/87  를 참고하자!

        - MBCS와 UNICODE가 호환되게 코딩하는 방법

1) 모든 문자열 상수는 TEXT() 키워드로 감싸준다. ex) "나는 가수다" => TEXT("나는 가수다")
2) char => TCHAR
3) char* => LPTSTR
4) const char* => LPCTSTR

- MBCS 와 UNICODE console 출력 함수 or 매크로
 
MBCS     출력 : cout / printf
UNICODE 출력   : wcout / wprintf
MBCS / UNICODE 호환 매크로 : _tprintf
- 일반적으로 사용 코드

1) MBCS 
 
1
2
char* message = new char[20];
sprintf( message, "%s", "정의란 무엇인가?" );

2) UNICODE 
 
1
2
wchar_t* message = new wchar_t[20];
swprintf( message, L"%s", L"정의란 무엇인가?);

MBCS UNICODE 호환 코드

1
2
TCHAR* widestring = new TCHAR[20];
wsprintf( widestring, TEXT("%s"), TEXT("정의란 무엇인가?") );


std::cout은 UNICODE로 된 문자열 정보를 제대로 출력하지 못한다. wcout 사용
호환되는 cout 계열은 없나 ㅋㅋ

UNICODE  문자열을 출력하려고 wcout를 사용하다보면 아무것도 출력이 안될때가 있다.
 아래 코드를 추가해주자.
 
1
2
3
4
#include <locale>
	
//호출
setlocale( LC_ALL, "Korean" );  // Console 화면에 한국어 출력






< 프로젝트 문자 집합 설정에 따른 CString 과 std::string의 차이! >

 

CString과 std::string은 어느정도 상호 호환이 가능한가를 알아보고, 
더불어 UNICODEMBCS 일 때 각각 어떻게 인식하는지 테스트 해 보았다.
 
 
■ 사용 문자집합 : UNICODE

- CStringUNICODE 지원 )


1
2
3
4
5
6
7
CString = char*;				// compile success
CString = const char*;			// compile success
CString = CString + const char*; 	              // compile success
CString = CString + CString;		        // compile success
	
CString = CString + std::string;		// compile error
CString = std::string; 			                      // compile error

- std::string


1
2
3
4
5
6
7
8
std::string = char*;				// compile success
std::string = const char*;			// compile success
	
std::string = CString + const char*; 		      // compile error
std::string = std::string + const char*;  	      // compile error
std::string = CString + CString;		// compile error	
std::string = CString;   			                      // compile error	
std::string = CString + std::string;		// compile error


■ 사용 문자집합 : MBCS

- CString

1
2
3
4
5
6
7
CString = char*;				// compile success
CString = const char*;			// compile success
CString = CString + const char*; 		      // compile success
CString = CString + CString;			// compile success
	
CString = CString + std::string;		// compile error
CString = std::string; 				              // compile error

- std::string

1
2
3
4
5
6
7
8
std::string = char*;				// compile success
std::string = const char*;			// compile success
std::string = CString + const char*; 		      // compile success
std::string = std::string + const char*; 	              // compile success
std::string = CString + CString;		// compile success	
std::string = CString;   			                      // compile success
	
std::string = CString + std::string;		// compile error

결론 : MBCS 와 UNICODE 호환까지 생각한다면 CString 사용하자.
         그리고 일반적으로 개발자들은 CString을 std::string보다 사용하기 편리하다고 생각하고 있다고 한다.
Posted by 닭꽝
비공개2011. 8. 9. 11:27
기존 프로그래밍 작성 관행은

class의 경우 선언부는 .h file 에 정의부는 .cpp 파일에 작성하였다.

그러나 Template의 경우 통상적으로 그렇게 구분해서 사용할 수가 없고, 선언과 정의를 하나의 파일에 작성해야한다. 

또, 보통 그렇게 사용한다. 다음처럼...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 선언부
template<typename T> 
class Queue
{
public:

	// 초기화 한다.
	void Clear();

public :
	T m_Data[100];

};


// 정의부
template < typename T > 
void Queue<T>::Clear()
{
	memset( m_Data, 0, sizeof(T)*100);
}
 

그러나 방법이 아주 없는것은 아닌데... 바로 .inl 파일을 사용하는 방법이다.

먼저, .inl 파일의 용도는 인라인 함수들은 헤더 파일에 기록하지 않고 인라인 함수용 파일을 따로 만들어
작성하고 관리 하기 위해 쓰인다.  그 때 사용하는 파일 확장자가 .inl 이다.

자 그럼! 분리해보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 선언부
template<typename T> 
class Queue
{
public:

	// 초기화 한다.
	void Clear();

public :
	T m_Data[100];

};

// include inline file
#include "queue.inl"


다음은 정의부이다.

 
1
2
3
4
5
6
7
// queue.inl 파일
// 정의부
template < typename T > 
void Queue<T>::Clear()
{
	memset( m_Data, 0, sizeof(T)*100);
}


이렇게 쓰면 된다. ㅎㅎㅎ
 

참고로, 이렇게 하는 방법은 앞서 거론했다싶이 일반적이지 않지만
일부 라이브러리나 3D 상용엔진에서는 저렇게 쓰기도 한다고 한다.
 
Posted by 닭꽝
비공개2011. 8. 8. 17:07

동일 이름의 템플릿 함수를 선택할때 Visual Studio 2010 컴파일러는 다음 순서대로 우선순위를 결정한다.

일반 함수 > 특수화 함수 > 템플릿 함수

테스트는 다음 코드로 하였다.


using namespace std;

// 템플릿 함수
// 템플릿 함수은 한정자( const ) 사용 불가!
template < typename T1, typename _T2 >
const T1& Max( const T1& _a, const _T2& _b)
{
	cout << "Max(const double& a, const double& b) 템플릿 버전 사용" << endl;
	return _a > _b ? _a : _b;
};

// 템플릿 함수 특수화
template <>
const double& Max<double>( const double& _a, const double& _b )
{
	cout << "Max(const double& a, const double& b) 특수화 버전 사용" << endl;
	return _a > _b ? _a : _b;
}

// 일반 함수
const double& Max( const double& _a, const double& _b )
{
	cout << "Max(const double& a, const double& b) 일반 함수 버전 사용" << endl;
	return _a > _b ? _a : _b;
}

void main()
{
	int Char1_HP = 300;
	int Char2_HP = 400;
	int MaxCharHP = Max( Char1_HP, Char2_HP );

	cout << "HP 중 가장 큰 값은" << MaxCharHP << "입니다." << endl << endl;


	float Char1_Exp = 250.0f;
	float Char2_Exp = 250.57f;
	float MaxCharExp = Max( Char1_Exp, Char2_Exp );

	cout << "경험치 중 가장 큰 값은" << MaxCharExp << endl << endl;


	double    Char2_MP = 300;
	double Char2_SP = 400.25f;
	double MaxValue2 = Max( Char2_MP, Char2_SP );

	cout << "MP와 SP 중 가장 큰 값은" << MaxValue2 << endl << endl;

	system("pause");
}






 

테스트 취지는, 템플릿 관련 정보를 찾아보던 중 특수화 함수 > 템플릿 함수 > 일반 함수 순서라고 설명이 나와서 확인 해 본것이다.

두곳을 봤는데 한곳이 저렇게 설명하였고, 다른 하나 곳은 컴파일러마다 판별 우선순위에 있어 차이가 있다라고 나온다.

다른 컴파일러에서는 확인을 안해봤지만 컴파일러마다 차이가 있을 것에 한표!!!

즉, 프로그래밍을 함에 있어 이러한 점을 고려하지 않는다면 의도하지 않는 함수가 호출 될 수 있다.

 
Posted by 닭꽝
비공개2011. 7. 20. 11:54
1
2
3
4
void Test( [ClassName] *list )
{
     ...
}


■ 코드 작성의도

나는 파라매터로 [ClassName]을 가르키는 포인터를 취하는 Test라는 함수를 만들었다.


1) 6.0  compile   : [error] STL로 인식. 파라메터로 list 템플릿을 사용했다고 오류!
2) 10.0 compile  : 빌드 성공
 
결론, 파라메타 이름은 물론, 변수명 등을 기존 라이브러리 이름과 동일시 하게 쓰지말자. 

Posted by 닭꽝
비공개2011. 7. 14. 14:42
뭉치님이 번역하신 주옥같은 글 ^^

그러나, 오래전에 번역이 중단된듯... 쿨럭;

http://blog.daum.net/shuaihan/15449014
Posted by 닭꽝
비공개2011. 7. 7. 16:28

- 프로그래밍 분야에서 자원(Resource) 이란 ?
사용을 일단 마치고 난 후엔 시스템에 돌려주어야하는 모든 것!


항목 13. 자원 관리에는 객체가 그만!
 


 - 자원 해제를 사용자가 일일이 하다보면 분명 실수 할 수 있다.
 


 ■ 자원 관리 방법론
 

 RAII    : 자원 관리에 객체를 사용하는 방법 . 자원 획득 후 바로 초기화!




 ■ 자원 관리 방식

 RCSP  : 참조 카운팅 방식.
              특정한 어떤 자원을 가리키는 외부 객체의 개수를 유지하고있다가 그 개수가 0이되면
              자원을 자동으로 삭제하는 스마트 포인터.


 

 ■ 자원 관리에 객체를 사용하는 방법
 

 1) 자원을 획득한 후 자원 관리 객체에 넘깁니다.
 

1
2
3
Investment* createInvestment();

std::tr1::shared_ptr<Investment> pInv1( createInvestment() ); // 생성 후 바로 자원관리 객체로 넘김


 2) 자원 관리 객체는 자신의 소멸자를 사용해서 자원이 확실히 해제되도록 합니다.




 ■ 제공되는 자원 관리 객체( RAII 클래스 )
 

 1) auto_ptr   : 가리키고 있는 대상에 대해 소멸자가 자동으로 delete를 불러주도록 설계!
                       복사 시 원본 삭제! 이 특성 때문에 일반적으로 사용하기가 힘듬.

                       표준 라이브러리에 포함
 


 2) shared_ptr : RCSP 방식.
                         TR1에서 제공.
                         STL 컨테이너 환경에서 사용하기에 적합.
 

 - 위 auto_ptr, shared_ptr 둘다 동적으로 할당된 배열은 지원 안함 -> vector 및 string으로 대체 해결!!
   ( 소멸시 delete[]가 아니라 delete 하기 때문! )
 

 - boost의 1) boost::scoped_array 와 2) boost::shared_array는 동적 할당된 배열을 지원함.




■ 책 요약

- 자원 누출을 막기 위해, 생성자 안에서 자원을 획득하고 소멸자에서 그것을 해제하는 RAII 객체를 사용합시다.

- 일반적으로 널리 쓰이는 RAII 클래스는 tr1::shared_ptr 그리고 auto_ptr 입니다.
   이 둘 가운데 tr1::shared_ptr 이 복사 시의 동작이 직관적이기 때문에 대개 더 좋습니다. 반면, auto_ptr은 복사되는
   객체( 원본 객체 )를 NULL로 만들어 버립니다.




 

항목 14. 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자

RAII 객체의 복사는 그 객체가 관리하는 자원의 복사 문제를 안고 가기 때문에, 그 자원을 어떻게 복사하느냐에 따라 RAII 객체의 복사 동작이 결정됩니다.



 

항목 15. 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자.

실제 자원을 직접 접근해야 하는 기존 API들도 많기 때문에, RAII 클래스를 만들 때는 그 클래스가 관리하는 자원을 얻을 수 있는 방법을 열어 주어야 합니다.

자원 접근은 명시적 변환 혹은 암시적 변환을 통해 가능합니다. 안전성만 따지면 명시적 변환이 대체적으로 더 낫지만, 고객 편의성을 놓고 보면 암시적 변환이 괜찮습니다. 



 

항목 16. New delete를 사용할 때는 형태를 반드시 갖추자.

new 표현식에 []를 썻으면, 대응되는 delete 표현식에도 []를 써야 합니다. 마찬가지로 new 표현식에 []를 안 썻으면, 대응되는 delete 표현식에도 []를 쓰지 말아야 합니다.



 

항목 17. New로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자
 


new로 생성한 객체를 스마트 포인터로 넣은 코드는 별도의 한 문장으로 만듭시다. 이것이 안 되어 있으면, 예외가 발생될  때 디버깅하기 힘든 자원 누출이 초래될 수 있습니다. 



 

Posted by 닭꽝