Programming Language/C, C++

StrSafe 함수들

MOLOKINI 2015. 9. 19. 12:36

문자열 함수는 말 그대로 문자열을 버퍼에 담고 출력하는 함수입니다.

주로 문자열 함수들은 문자열 버퍼의 포인터를 리턴하게 되는데요, 이 때문에 버퍼 오버플로우 현상이 일어날 수 있습니다.

 

TCHAR* alphabet = "ABCDEFGH"

TCHAR  buf[3];

_tcscpy(buf, alphabet);

 

이와 같은 경우, 담을 수 있는 버퍼(2글자 + NULL)보다 큰 포인터가 들어오게 되고 이 버퍼 이후에 진행될 스택의 내용을 문자열들이 덮어버려 의도하지 않은 결과를 가져올 수 있습니다.

 

이런 문제를 보완하기 위해 Windows에서는 안전한 문자열 함수들을 제공하고 있습니다.

 

strsafe.h 헤더를 포함시키면 사용할 수 있으며 그 종류들은 아래와 같습니다.

 

기존 함수 안전한 문자열 함수 
 strcpy StringCbCopy, StringCbCopyEx
StringCchCopy, StringCchCopyEx 
 strncpy StringCbCopyN, StringCbCopyNEx
StringCchCopyN, StringCchCopyNEx 
 strcat StringCbCat, StringCbCatEx
StringCchCat, StringCchCatEx 
 strncat StringCbCatN, StringCbCatNEx
StringCchCatN, StringCchCatNEx 
 sprintf StringCbPrintf, StringCbPrintfEx
StringCchPrintf, StringCchPrintfEx 
 vsprintf StringCbVPrintf, StringCbVPrintfEx
StringCchVPrintf, StringCchVPrintf 
 gets StringCbGets, StringCbGetsEx
StringCchGets, StringCchGetsEx 
 strlen StringCbLength
StringCchLength 

 

이 함수들을 보면, Cb, Cch, Ex가 있습니다. 이 차이는

Cb : 버퍼의 크기를 인자로 받는다. (버퍼가 몇 바이트의 크기인가)

Cch : 버퍼의 길이를 인자로 받는다. (버퍼가 문자열 몇개를 담을 수 있는가)

Ex : 버퍼 패딩, 자름 등 추가 기능을 가진다.

 

Ex를 제외한 Cb, Cch 함수들을 설명하도록 하겠습니다.

- 이 함수들은 기존 함수들이랑 동일한 문자열을 받도록 되어 있습니다.

- 또한 TCHAR를 인자로 쓴다면 원형 그대로를, WCHAR라면 함수의 맨끝에 W, Ansi 문자열이라면 A를 붙여주어야 합니다.

- StringCbCopyW, StringCbCopyA

- 그런데, W나 A를 붙이지 않고 그냥 쓰면 알아서 바꿔줍니다.

 

1. StringCbCopy, StringCchCopy

HRESULT StringCbCopy

   OUT LPTSTR pszDest,                               // 복사 결과를 저장할 버퍼

   IN    size_t   cbDest, (sizeof(TCHAR))            // 복사 결과를 저장할 버퍼의 버퍼의 크기 (pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc                                // 복사 원본 (NULL 포함된 문자열)

 

HRESULT StringCbCopy ( 

   OUT LPTSTR pszDest,

   IN    size_t   cchDest, (STRSAFE_MAX_CCH)    // 위와 같고, NULL 포함한 pszSrc의 길이

   IN    LPCTSTR pszSrc

)

 

위에서 설명한 것처럼 버퍼의 크기를 인자로 받을 것인지, 길이를 인자로 받을 것인지 이외 두 함수간의 다른 점은 없습니다.

strcpy, wcscpy, _tcscpy, lstrcpy.... 등의 문자열 복사 함수들을 대체할 수 있습니다.

 

리턴형은 HRESULT로

SUCCEEDED, FAILED

 

 

2. StringCbCopyN, StringCchCopyN

HRESULT StringCbCopyN(

   OUT LPTSTR pszDest,                               // 복사 결과를 저장할 버퍼

   IN    size_t   cbDest, (sizeof(TCHAR))            // 복사 결과를 저장할 버퍼의 크기 (pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc,                               // 복사 원본

   IN    size_t     cbSrc                                 // 복사 원본 중에서 복사하고 싶은 만큼의 버퍼 크기

)

 

HRESULT StringCchCopyN(

   OUT LPTSTR pszDest,                                // 복사 결과를 저장할 버퍼

   IN    size_t   cchDest, (STRSAFE_MAX_CCH)    // 복사 결과를 저장할 버퍼의 길이 (pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc,

   IN    size_t     cchSrc                                 // 원본 문자열(pszSrc)에서 복사하고 싶은 만큼의 길이

)

 

원본 문자열에서 원하는 버퍼/길이 만큼 복사하는 함수로

strncpy, wcsncpy, _tcsncpy를 대체합니다.

 

 

3. StringCbCat, StringCchCat

HRESULT StringCbCat(

   OUT LPTSTR pszDest,                               // 이어 붙일 문자열의 앞부분

   IN    size_t   cbDest, (sizeof(TCHAR))            // 저장할 버퍼의 총 크기 (pszDest + pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc,                               // 이어 붙일 문자열

)

 

HRESULT StringCchCat(

   OUT LPTSTR pszDest,                               // 이어 붙일 문자열의 앞부분

   IN    size_t   cchDest,                               // 저장할 문자열의 총 길이 (pszDest + pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc,                               // 이어 붙일 문자열

)

 

StringCbCat, StringCchCat 함수는 2개의 문자열을 서로 합치는 함수로

pszDest + pszSrc 순서로 합친다고 보시면 됩니다.

 

이 함수는 strcat, lstrcat, wcscat, _tcscat.... 등을 대체합니다.

 

 

4. StringCbCatN, StringCchCatN

HRESULT StringCbCatN(

   OUT LPTSTR pszDest,                               // 이어 붙일 문자열의 앞부분

   IN    size_t   cbDest, (sizeof(TCHAR))            // 저장할 버퍼의 총 크기 (pszDest + pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc,                               // 이어 붙일 문자열

   IN    size_t   cbMaxAppend                       // pszSrc의 문자열 중에서 pszDest에 연결하고 싶은 만큼의 버퍼 크기

)

 

HRESULT StringCchCatN(

   OUT LPTSTR pszDest,                               // 이어 붙일 문자열의 앞부분

   IN    size_t   cchDest,                               // 저장할 문자열의 총 길이 (pszDest + pszSrc + 1 NULL 포함)

   IN    LPCTSTR pszSrc,                               // 이어 붙일 문자열

   IN    size_t   cbMaxAppend                       // pszSrc의 문자열 중에서 pszDest에 연결하고 싶은 만큼의 문자열 길이

)

 

StringCbCatN, StringCchCatN 함수는 

눈치 채셨겠지만 위의 StringCchCopyN과 마찬가지로 pszSrc에서 pszDest로 문자열을 이어 붙일 때 전부 붙이지 않고 pszSrc의 길이/버퍼를 지정한 만큼(cbMaxAppend)만 복사해 붙입니다.

 

이 함수는 strncat... 등을 대체합니다.

 

 

5. StringCbPrintf, StringCchPrintf

HRESULT StringCbPrintf(

   OUT LPTSTR pszDest,                               // 문자열을 저장할 버펴 변수

   IN    size_t   cbDest, (sizeof(TCHAR))            // 저장할 버퍼의 총 크기 (pszDest + 1 NULL 포함)

   IN    LPCTSTR pszFormat,                          // 문자열 포맷 (ex : _T("%s")

   ........                                                      // 저장 할 문자열

)

 

HRESULT StringCchPrintf(

   OUT LPTSTR pszDest,                                // 문자열을 저장할 버펴 변수

   IN    size_t   cchDest, (_countof(pszDest))      // 저장할 문자열의 총 길이 (pszDest + 1 NULL 포함)

   IN    LPCTSTR pszFormat,                          // 문자열 포맷 (ex : _T("%s"))

   ........                                                      // 저장 할 문자열 변수나 문자열 (ex: _T("Hello!"))

)

 

문자열을 버퍼에 담는 변수로 Printf 처럼 3번째 인자 이후로는 표현하고 싶은 내용이 여러개 일 경우 3번째 포맷 인자에 맞추어 계속 변수들을 쓸 수 있습니다.

 

예를 들면..

TCHAR* pszSanE = "산이";

StringCchPrintf(pszDest, _countof(pszDest), _T("%s물과 백두%s"), _T("동해"), pszSanE);

 

라고 한다면 pszDest에는

동해물과 백두산이\0

가 들어가게 됩니다.

 

 

6. StringCbVPrintf, StringCchVPrintf

HRESULT StringCbVPrintf(

   OUT LPTSTR pszDest,                               // 문자열을 저장할 버펴 변수

   IN    size_t   cbDest, (sizeof(TCHAR))            // 저장할 버퍼의 총 크기 (pszDest + 1 NULL 포함)

   IN    LPCTSTR pszFormat,                          // 문자열 포맷 (ex : _T("%s")

   IN    va_list    argList                                // 저장 할 문자열의 리스트

)

 

HRESULT StringCchVPrintf(

   OUT LPTSTR pszDest,                                // 문자열을 저장할 버펴 변수

   IN    size_t   cchDest, (_countof(pszDest))      // 저장할 문자열의 총 길이 (pszDest + 1 NULL 포함)

   IN    LPCTSTR pszFormat,                          // 문자열 포맷 (ex : _T("%s"))

   IN    va_list    argList                                // 저장 할 문자열 변수나 문자열의 리스트 (ex: _T("Hello!"))

)

 

가변 인자를 처리하는 안전한 printf 함수입니다.

vsprintf, vswprintf, _vsprintf....를 대체합니다.

 

가변 인자에 대해 짤막하게 설명해드리면, 리스트 형태로 인자의 갯수를 변경할 수 있다는 것을 말합니다.

인자가 1개, 2개, 3개... 가변적으로 변한다는 이야기입니다.

실제로 printf에서 문자열을 출력할 때 문자열의 포맷과 변수의 갯수를 제한없이 정해줄 수 있는 것과 같은 개념으로 이해하시면 됩니다. (int printf(const char* _Format, ......) <- 이 ...이 바로 가변 인자입니다.)

가변 인자로 함수를 만들려면 가변 인자를 사용해야하는데요 

가변 인자 매크로들은 va_로 시작하며 stdarg.h에 정의되어 있습니다. (내용이 길어지기 때문에 다른 포스팅에서 가변인자에 대해 정리하도록 하겠습니다.)

 

 

7. StringCbGets, StringCchGets

HRESULT StringCbGets(

   OUT LPTSTR pszDest,                               // 문자열을 저장할 버펴 변수

   IN    size_t   cbDest, (sizeof(TCHAR))            // 저장할 버퍼의 총 크기 (pszDest + 1 NULL 포함)

)

 

HRESULT StringCchGets(

   OUT LPTSTR pszDest,                                // 문자열을 저장할 버펴 변수

   IN    size_t   cchDest, (_countof(pszDest))      // 저장할 문자열의 총 길이 (pszDest + 1 NULL 포함)

)

 

fgets, gets의 안전한 문자열 함수로 공백을 포함한 문자열을 입력받고 버퍼에 저장합니다.

cchDest, cbDest를 초과한 입력은 잘려서 pszDest로 저장됩니다.

 

 

8. StringCbLength, StringCchLength

HRESULT StringCbLength(

   IN    LPCTSTR psz,                  // 문자열의 크기를 체크할 버펴 변수

   IN    size_t   cbMax,                // psz로 입력받을 수 있는 최대 버퍼 크기

   OUT size_t   *pcb                   // psz의 문자열 버퍼 크기 리턴

)

 

HRESULT StringCchLength(

   IN    LPCTSTR psz,                   // 문자열의 크기를 체크할 버펴 변수

   IN    size_t   cchMax,               // psz로 입력받을 수 있는 최대 문자열의 길이 (MAX_PATH, MAX_FILENAME 등등)

   OUT size_t   *pch                   // psz의 문자열 길이 리턴

)

 

strlen, wcslen, _tcslen 함수를 대체하는 문자열 길이 리턴 함수입니다.

두번째 인자(cchMax, cbMax)는 psz의 길이가 아니라 개발하시면서 정의해둔 문자열의 최대 길이를 의미합니다.

예를 들면...

 

#define MAX_PATH 255          // 입력받는 경로의 최대 길이

 

void pathlength(LPCTSTR lpszPath)

{

        size_t len = 0;

        StringCchLength(lpszPath, MAX_PATH, &len);

}

 

요런 형태로 사용하실 수 있습니다.

'Programming Language > C, C++' 카테고리의 다른 글

C++ 기본 자료형  (0) 2016.05.06
네임드 파이프 예제  (0) 2016.04.30
C 데이터, 스택, 힙 영역  (0) 2014.12.08
C++ Volatile 키워드  (0) 2014.11.15
C++ 포인터와 레퍼런스의 차이  (0) 2014.11.12