출처: http://blog.naver.com/jmj1130?Redirect=Log&logNo=100042140754

열나게 맞고 한대 더 맞는 느낌으로...유니코드 대책 Vc,C++,Tip모음

2007/09/17 19:04

복사 http://blog.naver.com/jmj1130/100042140754

http://i-sac.co.kr/blog/archives/2005/08/index.html


----------------------------------------------------------------------
형 변환
//UNICODE->ANSI
int nAsciiLen = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL);
char *szXMLFilePath = new char[nAsciiLen+1];
WideCharToMultiByte( CP_ACP, 0, buffer, -1, szXMLFilePath, nAsciiLen+1, NULL, NULL );


//ANSI->UNICODE
char appName[256];
char logFolder[MAX_PATH];
char logFileName[128];

m_clsResourceProvider->GetParameter("LogFolder",logFolder);
m_clsResourceProvider->GetParameter("LogFileName",logFileName);
m_clsResourceProvider->GetParameter("AppName",appName);

m_clsLogger = new CLog(appName);

/*
 MultiByteToWideChar( CP_ACP, 0, UserName,
        strlen(UserName)+1, wszUserName,  
     sizeof(wszUserName)/sizeof(wszUserName[0]) );
*/
_TCHAR _appName[512];
_TCHAR _logFolder[MAX_PATH*2];
_TCHAR _logFileName[256];

MultiByteToWideChar( CP_ACP, 0, appName, strlen(appName)+1, _appName,sizeof(_appName)/sizeof(_appName[0]) );
MultiByteToWideChar( CP_ACP, 0, logFolder, strlen(logFolder)+1, _logFolder,sizeof(_logFolder)/sizeof(_logFolder[0]) );
MultiByteToWideChar( CP_ACP, 0, logFileName, strlen(logFileName)+1, _logFileName,sizeof(_logFileName)/sizeof(_logFileName[0]) );

wsprintf((LPWSTR)buffer ,_T( "%s\\%s") ,_logFolder,_logFileName);

CFileLogAppender * pFileLogAppender = new CFileLogAppender(nsCLog::mylog, (LPSTR)buffer);
if(false != m_clsLogger->addAppender(pFileLogAppender))
{
m_clsLogger->writeLog(nsCLog::warning, "CIVRLogHandlerApp | NULL |アプリケーションが起動されました | NULL |");
}


---------------------------------------------------------------
문자의 개수 : sizeof(szBuffer) / sizeof(TCHAR)

문자열의 길이 : sizeof(szBuffer) * sizeof(TCHAR)

적절한 매크로를 만들어 사용하면 고민에서 해방될까?

-------------------------------------------------------------------
TCHAR std::string 대책
// ok but not recommended
typedef basic_string  char_traits,
  allocator >
  tstring;

// better, recommended
#ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif


---------------------------------------------------------------------------------------
http://www.reiot.com/blogmeme/blog/index.php?blog_code=reiot&article_id=120

 
게임 서버에서 모든 문자열을 유니 코드(UTF-16)로 사용한다고 하면, 메모리를 2배나 사용할텐데 메모리나 성능에 문제가 생기면 어쩌냐는 질문을 많이 받는다. 그 정도는 괜찮다고 말하지만, 내심 걱정이 되는 것이 사실이다. (이전 프로젝트에서 서버 프로파일링을 해보니 실제로 std::string 이 차지하는 부하가 무지막지했다. 더군다나 이번엔 std::wstring... STL string 혐오론자가 보면 두려움에 치를 떨지도... -┌)

유니 코드를 쓰는 이유는 꽤나 많지만, 그 중에서도 가장 큰 이유를 꼽자면, i18n 그리고 l10n 이 필요해지는 시점에서 추가적인 작업을 최소화한다는 데 있다. 그런데, 실제로 저 작업을 처음부터 끝까지 겪어보지 못한 나로서는 웬지 지금 하고 있는 짓이 무의미하고 귀찮게만 느껴지기도 한다. 대충 나열해 보자면...

- strcpy() 의 친구들을 _tcscpy() 친구들로 교체
- 모든 문자열의 앞뒤로 _T( ) 를 붙임 <-- 이게 제일 귀찮다!! 그냥 regexp 로 글로벌 변경하는 게 짱이다.
- 모든 Win32 API 들의 유니코드 지원여부 체크. 가끔 LPCTSTR 이 아닌 char * 만을 받는 함수들을 만나면 좀 난감하다. 특히 winsock2의 주소 쿼리 함수들...
- 문자열 <-> 바이트배열 변환시 /sizeof(TCHAR) 또는 * sizeof(TCHAR) 꼭 해주기
- 문자 배열을 TCHAR []로, 바이트 배열은 BYTE []로, char * 는 LPCTSTR 로 변경하기
- 모든 텍스트 파일을 UTF-8 인코딩으로 저장해서 체크인 할 때마다, 소스세이프의 투덜거림을 달래기
- wstring 을 타이핑 할 때마다 '이렇게 하면 오히려 더 느려질텐데...' 라며 잠시 근심하기

사실, l10n 을 해야 할 때가 되었다는 것은 하늘의 축복이므로 기쁜 마음으로 하면 될텐데... 하고 한숨을 지어 본다. (성공한 개발자는 이 말의 의미를 잘 모를꺼다. 헹.) 그러고보니, 아직 더 알아봐야 하는 것들도 있다.

- 지역화 메시지 : 클라이언트 서버에 사용하는 다양한 다국적 출력 메시지들을 얼마나 아름답게 지역화하는가~
- DB에다가 유니코드 charset 을 사용하기 : 몇몇 고수들의 말로는 그냥 그나라 charset 을 사용하는 게 제일 좋다고 하더라만은... 아직은 와닿지 않는 이야기.


--------------------------------------------------------------------------------------
C++의 기본은 문자열 조작이라고 생각한다. 이참에 문자열을 비롯한 자료형을 정리하자..
1. C 자료형

    char (1) , short (2) , int (4) , long (4), float (4) , double (8) , bool  
    문자 : char
    char szName[20] = "kim";


2. WIN API 자료형

BYTE (1,unsigned char)  
WORD (2,unsigned short)
UNIT (4, unsigned int) , 
     DWORD (4,unsigned long)
LONG (4,long)
BOOL
    문자 : UCHAR (unsigned char)
    핸들 : 대상을 구분하는 4바이트 정수(HWND, HDC 등)

    MBCS문자(열)                 유니코드문자(열)           자동매크로문자(열)
    char                                     wchar_t                       TCHAR
    LPSTR(char*)                    LPWSTR(wchar_t*)         LPTSTR
    LPCSTR(const char*)      LPCWSTR                         LPCTSTR

    (참조1) 문자열에 대해 그냥 습관적으로 LPTSTR 또는 LPCTSTR 를 써라
    (참조2) 헝가리안명명법
                   w(WORD) , dw(DWORD) , i(int) , b(BOOL) , ch(문자) , sz(문자열) , h(핸들)
                   cb(바이트수) , a(배열)
(참조3) OLECHAR(wchar_t), LPOLESTR(LPWSTR), LPCOLESTR(LPCWSTR), OLESTR(x) = _T(x)


3. COM 스트링

    BSTR : 문자열길이를 시작전에 저장하고, 이어서 유니코드문자열을 저장하는 방식
                  1> LPCWSTR ->  BSTR : 생성안됨. 생성함수를 이용해야함
                      BSTR bstr = sysAllocString(L"Hi Bob"); // 메모리할당
                      sysFreeString(bstr); // 메모리제거
                  2> BSTR  ->  LPCWSTR : 형변환 가능

    VARIANT : 문자열이 들어올때  BSTR과 동일

4. CRT(c runtime library) 지원 스트링클래스

    _bstr_t : BSTR랩퍼클래스, 메모리할당/제거를 자동으로 수행
                  1> LPCSTR, LPCWSTR  -> _bstr_t
                               _bstr_t bs1 = "char string";  // 생성
                  2> _bstr_t  ->  LPCSTR, LPCWSTR
                               LPCSTR psz1 = (LPCSTR)bs1; // 형변환
                  3> _bstr_t  ->  BSTR : 형변환안됨. 함수이용
                               BSTR bstr = bs1.copy();
                               sysFreeString(bstr);  // BSTR은 사용후 메모리해제를 해야하는 불편이있음..

    _variant_t : VARIANT랩퍼클래스, 메모리할당/제거를 자동으로 수행
                  1> LPCSTR, LPCWSTR  -> _variant_t
                               _variant_t v1 = "char string"; // 생성
                  2> _variant_t  -> _bstr_t  ->  LPCSTR, LPCWSTR
                               LPCSTR psz1 = (LPCSTR)(_bstr_t)v1;  //형변환

5. ATL 지원 스트링클래스

    CComBSTR : BSTR랩퍼클래스, 메모리할당/제거를 자동으로 수행
                  1> LPCSTR, LPCWSTR  ->  CComBSTR
                               CComBSTR bs1 = "char string"; // 생성
                  2> CComBSTR  ->  BSTR   -> LPCWSTR
                               BSTR bstr = (BSTR)bs1;  // 형변환

                  (참조) BSTR -> CComBSTR  
                               CComBSTR bs2; bs2.Attach(W2BSTR(L"Bob"))
                               
    CComVariant : VARIANT랩퍼클래스, 메모리할당/제거를 자동으로 수행
                  1> LPCSTR, LPCWSTR  ->  CComVariant
                               CComVariant bs1 = "char string"; // 생성
                  2> CComVariant  ->  CComBSTR   ->  BSTR   -> LPCWSTR
                               CComBSTR bs2 = bs1.bstrVal;

6. STL 스트링

    string  
                  1> LPCSTR -> string
                                string  str = "char string"; //생성
                  2> string -> LPCSTR : 형변환 안됨. 함수이용
                                LPCSTR psz = str.c_str();
    wstring
                   1> LPCWSTR -> wstring
                                wstring  str = "wide char string"; //생성
                  2> wstring -> LPCWSTR : 형변환 안됨. 함수이용
                                LPCWSTR psz = str.c_str();

7. MFC 스트링

    CString
                  1> LPCSTR, LPCWSTR  ->  CString
                                CString  str = "char string"; //생성
                  2> CString  -> LPCTSTR : 
                                LPCTSTR  lpsz = (LPCTSTR)str; //형변환

                  (참고)  CString  -> LPTSTR :  함수이용

                               LPTSTR lptsz  = str.GetBuffer(0); str.ReleaseBuffer(); //  올바른 사용
                               LPTSTR lptsz  = (LPTSTR)(LPCTSTR)str  //  잘못된 사용
                               CString  -> BSTR  
                               BSTR bstr = str.AllocSysString(); sysFreeString(bstr)

8. VC7 스트링

    String : .NET에서 새로 정의한 스트링 클래스
                               String* s1 = S"this is nice"; // 생성
                               CString s2(s1); // 형변환

AND