정리

ATL and MFC String Conversion Macros 사용 시 주의할 점

저장소/VC++

출처 MSDN : https://msdn.microsoft.com/ko-kr/library/87zae4a3(v=vs.120).aspx


요약:

loop 내에서는 A2W 등의 ATL 3.0 매크로를 쓰지 마라. 스택 오버플로우 문제가 발생할 수 있다.

어쩔 수 없이 써야한다면 ATL 7.0 매크로(CA2WEX class 등)를 사용해야 한다.




ATL and MFC String Conversion Macros

Visual Studio 2013

이 항목에서 설명하는 문자열 변환 매크로는 ATL과 MFC에 모두 사용 가능합니다. MFC 문자열 변환에 대한 자세한 내용은 TN059: MFC MBCS/유니코드 변환 매크로 사용 과 MFC 매크로 및 전역을 참조하세요.

ATL 7.0에는 기존 매크로에 비해 크게 향상된 여러 가지 새 변환 클래스와 매크로가 도입되었습니다.

새로운 문자열 변환 클래스 및 매크로 이름의 형식은 다음과 같습니다.

C SourceType 2[C]DestinationType[EX]

다음은 각 문자에 대한 설명입니다.

  • SourceType 및 DestinationType은 아래 테이블에 설명되어 있습니다.

  • [C]는 대상 형식이 상수여야 하는 경우 표시됩니다.

  • [EX]는 버퍼의 초기 크기가 템플릿 인수로 지정되어야 하는 경우 표시됩니다.

    SourceType/DestinationType

    설명

    A

    ANSI 문자열입니다.

    W

    유니코드 문자열입니다.

    T

    일반 문자열입니다. _UNICODE가 정의된 경우에는 W와 동일하며, 그렇지 않은 경우에는 A와 동일합니다.

    OLE

    OLE 문자열입니다. W와 동일합니다.

예를 들어 변환된 문자열을 변경하지 않고 유니코드 문자열에서 일반 문자열로 변환하려면 CW2CT를 사용합니다.

주의 정보 주의

위에 나열된 패턴의 일부 순열은 지원되지 않습니다. CA2CW 및 CW2CA와 CA2CWEX 및 CW2CAEX는 지원되지 않습니다. OLE 문자열 변환의 경우에는 COLE2T 및 CT2OLE와 COLE2CTCOLE2TEXCOLE2CTEXCT2COLECT2OLEEX 및 CT2COLEEX만 지원됩니다. 자세한 내용은 atlconv.h를 참조하세요.

변환된 문자열이 64자 이하일 가능성이 높은 경우에는 CW2CTEX<64> 등의 EX 버전을 사용하여 스택에서 공간을 절약할 수 있습니다.

참고 참고

BSTR 문자열 간에 변환할 때는 CComBSTR 클래스를 사용하는 것이 좋습니다. BSTR로 변환하려면 기존 문자열을 CComBSTR의 생성자로 전달합니다. BSTR에서 변환하려면 COLE2T와 같은 COLE2[C]DestinationType[EX]를 사용합니다.

버퍼가 필요한 새 변환 클래스(CA2AEXCA2WEXCW2AEX 및 CW2WEX)는 고정 크기 정적 버퍼를 사용하여 변환 결과를 저장합니다. 결과가 너무 커서 정적 버퍼에 포함할 수 없는 경우 클래스는 malloc를 사용하여 메모리를 할당함으로써 개체가 범위를 벗어나면 메모리를 해제합니다. 따라서 이전의 텍스트 변환 매크로와는 달리 이러한 클래스를 루프에서도 안전하게 사용할 수 있으며 스택이 오버플로되지 않습니다.

ATL 7.0에 도입된 변환 매크로는 입력 NULL 문자열을 인식하도록 최적화되어 있습니다. 입력 매개 변수가 NULL이면 이러한 매크로는 메모리를 할당하지 않고 NULL을 반환합니다.

기본적으로 ATL 변환 클래스와 매크로는 현재 스레드의 ANSI 코드 페이지를 변환에 사용합니다. CA2WEX 또는 CW2AEX 클래스 기반 매크로를 사용하는 특정 변환에 대해 이 동작을 재정의하려는 경우 코드 페이지를 클래스 생성자에 대한 두 번째 매개 변수로 지정합니다.

보안 정보 보안 정보

버퍼 오버런 문제 발생 가능성을 방지하려면 문자열을 이러한 매크로로 전달하기 전에 문자열의 길이를 확인합니다. 스택 오버플로는 try/except를 통해서도 catch할 수 있는 예외입니다.

이전 문자열 변환 매크로와 새로운 문자열 변환 클래스의 몇 가지 중요한 차이점은 다음과 같습니다.

이전 ATL 3.0 변환 매크로

새 ATL 7.0 변환 클래스

스택에 메모리를 할당합니다.

작은 문자열에 대해 스택 메모리를 사용합니다. 스택이 충분히 크지 않으면 힙을 사용합니다.

함수가 종료되면 문자열이 해제됩니다.

변수가 범위를 벗어나면 문자열이 해제됩니다.

예외 처리기에서는 사용할 수 없습니다.

예외 처리기에서 사용할 수 있습니다.

루프에 사용하기 적합하지 않습니다. 함수가 종료될 때까지 메모리 사용이 증가합니다.

루프에서 사용할 수 있습니다. 루프 범위가 적용되므로 각 반복에서 메모리가 해제됩니다.

큰 문자열의 경우에는 효율적이지 않습니다. 스택 공간이 제한됩니다.

큰 문자열에 사용해도 문제가 없습니다. 문자열은 힙에 할당됩니다.

보통 USES_CONVERSION을 정의해야 합니다.

USES_CONVERSION을 정의하지 않아도 됩니다.

OLE의 의미가 OLE2ANSI 정의에 따라 달라집니다.

OLE는 항상 W와 동일합니다.

//Example 1 
// Convert LPCWSTR to LPCSTR. 
void ExampleFunction1(LPCWSTR pszW)
{
   // Create an instance of CW2A, called pszA, 
   // and initialize it with pszW.
   CW2A pszA(pszW);
   // pszA works like an LPCSTR, and can be used thus:
   ExampleFunctionA(pszA);  
   // Note: pszA will become invalid when it goes out of scope.
}

// Example 2 
// Use a temporary instance of CW2A. 
void ExampleFunction2(LPCWSTR pszW)
{
   // Create a temporary instance of CW2A, 
   // and initialize it with pszW.
   ExampleFunctionA(CW2A(pszW));
   // Note: the temporary instance becomes invalid  
   // after the execution of the statement above.
}

// Example 3 
// Incorrect use of conversion macros. 
void ExampleFunction3(LPCWSTR pszW)
{
   // Create a temporary instance of CW2A, 
   // save a pointer to it and then delete 
   // the temportary instance.
   LPCSTR pszA = CW2A(pszW);
   // The pszA in the following line is an invalid pointer, 
   // as the instance of CW2A has gone out of scope.
   ExampleFunctionA(pszA);
}

아래 코드는 효율적인 코드가 아닙니다.

LPCTSTR szr = CA2T(szReplaceFile);

ATL 3.0 매크로를 사용하면 다음 코드를 사용할 수 있습니다.

LPCTSTR szr = A2T(szReplaceFile);   

현재 함수가 종료될 때까지 변환 함수가 할당한 메모리가 해제되지 않습니다. 그러나 새 클래스에서는 위와 같은 코드가 작동하지 않습니다.

아래 코드는

LPCTSTR szr = CA2T(szReplaceFile);   

다음 코드 조각과 일치합니다.

LPCTSTR szr;
{
   CA2T temp(szReplaceFile);
   szr = temp.operator LPTSTR();
}   

임시 개체가 제거되면 해당 임시 개체가 할당하고 캐스트 연산자에서 반환된 메모리도 제거되므로, szr의 값을 사용하면 원하는 결과를 얻을 수 없습니다.

대신 다음 코드를 사용합니다.

CA2T szr(szReplaceFile);   

캐스트 연산자는 CA2T 개체를 LPCTSTR과 같이 표시합니다.

기본 정적 버퍼 크기는 128자입니다. 특정 변환에 대해 버퍼 크기를 변경해야 하는 경우 매크로의 EX 버전을 사용하고 템플릿 인수로 버퍼 크기를 지정합니다.

// Example 4 
// Changing the size of the buffer. 
void ExampleFunction4(LPCWSTR pszW)
{
   // Use a 16-character buffer.
   ExampleFunctionA(CW2AEX<16>(pszW));
}

아래에는 클래스의 생성자에 대해 코드 페이지를 두 번째 매개 변수로 지정하는 예가 나와 있습니다.

// Example 5 
// Specifying the code page. 
void ExampleFunction5(LPCWSTR pszW)
{
   // Convert to the Macintosh code page
   ExampleFunctionA(CW2A(pszW, CP_MACCP));
}

아래 테이블에 나와 있는 원래 텍스트 변환 매크로도 계속 사용할 수 있습니다.

ATL 3.0 문자열 변환 매크로

A2BSTR

OLE2A

T2A

W2A

A2COLE

OLE2BSTR

T2BSTR

W2BSTR

A2CT

OLE2CA

T2CA(사용되지 않음. 대신 T2CA_EX 또는 CT2CA 사용)

W2CA

A2CW

OLE2CT

T2COLE

W2COLE

A2OLE

OLE2CW

T2CW

W2CT

A2T

OLE2T

T2OLE

W2OLE

A2W

OLE2W

T2W

W2T

이러한 매크로 사용을 위한 구문은 다음과 같습니다.

MACRONAME( string_address )

예를 들면 다음과 같습니다.

A2W(lpa);

매크로 이름에서 소스 문자열 형식은 왼쪽에 있고(예: A) 대상 문자열 형식은 오른쪽에 있습니다(예: W). A는 LPSTR을, OLE는 LPOLESTR을, TLPTSTR을, W는 LPWSTR을 나타냅니다.

이름에 C가 있는 매크로는 소스 문자열을 const 문자열로 변환합니다. 예를 들어 W2CA는 LPWSTR을 LPCSTR로 변환합니다.

따라서 A2W는 LPSTR을 LPWSTR로 변환하고 OLE2T는 LPOLESTR을 LPTSTR로 변환하는 식으로 변환이 수행됩니다.

ATL 문자열 변환 매크로의 동작은 적용 중인 컴파일러 지시문(있는 경우)에 따라 달라집니다. 소스와 대상 형식이 같으면 변환이 수행되지 않습니다. 컴파일러 지시문은 T 및 OLE를 다음과 같이 변경합니다.

적용되는 컴파일러 지시문

T의 변경 결과

OLE의 변경 결과

없음

A

W

_UNICODE

W

W

OLE2ANSI

A

A

_UNICODE 및 OLE2ANSI

W

A

대상 형식이 BSTR인 경우를 제외하고 _alloca를 사용하여 대상 문자열을 만듭니다. _alloca를 사용하는 경우 스택 외부에 메모리가 할당되므로 함수가 반환될 때 자동으로 정리됩니다. 이 매크로는 기본적으로 한 번에 최대 500KB까지만 변환합니다.

ATL 문자열 변환 매크로를 사용할 때는 컴파일러 오류를 방지하기 위해 함수 시작 부분에 USES_CONVERSION 매크로를 지정합니다. 예를 들면 다음과 같습니다.

void StringFunc(LPSTR lpsz)
{
   USES_CONVERSION;

   LPWSTR x = A2W(lpsz);
   // Do something with x
   wprintf_s(L"x is %s", x);
}

헤더 파일: AtlBase.h, AtlConv.h(AtlConv.h에 선언됨)


'저장소 > VC++' 카테고리의 다른 글

across DLL boundaries (cross-DLL problem)  (0) 2016.04.08
VS2012의 tuple  (0) 2014.09.17
[펌] shlwapi 의 파일 경로 관련 API 모음  (0) 2014.08.13
strftime format 좀 기억하자!  (0) 2014.08.08
SQLite - Syntax  (0) 2014.05.27