본문 바로가기

C++

유니코드 문자열 처리

TCHAR를 쓰면 tcs~() 함수들을 프로젝트속성에 따라 컴파일러가 멀티바이트와 유니코드 알아서 바꿔준다.

어떤함수들이 있는지, 사용법과 함께 정리해보자.

 

 

 

1.       Formatted I/O

MACRO

ANSI

UNICODE

설명/예제

_tprintf

printf

wprintf

콘솔창에서 출력하기위해 쓴다.

_tprintf( _T("format %s %d"), (TCHAR*)szTemp, (int)nIdx);

_ftprintf

fprintf

fwprintf

 파일에 출력하는 용도. 파일 핸들이 필요하다.

_ftprintf( (FILE*) _tfopen(_T("filename"), _T("w")), _T("format %s"), szTemp);

_stprintf

sprint

swprintf

버퍼에 포맷을 넣는용도

TCHAR szDec[128] = {0,};

_stprintf(szDec, _T("format %s"), szTemp);

_sntprintf

_snprintf

_snwprintf

 위에꺼(sprintf)랑 용도는 같지만 버퍼사이즈가 들어간다.

_sntprintf(szDec, 128, _T("format %s"), szTemp);

_vtprintf

vprintf

vwprintf

 가변인자 리스트를 사용하는 printf

va_list lpStart;
va_start(lpStart, szFormat);
_vtprintf(szFormat, lpStart);
va_end(lpStart);

_vftprintf

vfprintf

vfwprintf

가변인자 리스트를 사용하는 fprintf

_vstprintf

vsprintf

vswprintf

가변인자 리스트를 사용하는 sprintf

_vsntprintf

_vsnprintf

_vsnwprintf

가변인자 리스트를 사용하는 snprintf

_tscanf

scanf

wscanf

값 입력함수

int num;

TCHAR szText[128] = {0,};

 

_tscanf(_T("%d"), &num);

_tscanf(_T("%s"), szText);

_ftscanf

fscanf

fwscanf

파일에서 읽어온다.

FILE* fp = _tfopen(_T("filename"), _T("w"));

int num;

TCHAR szText[128] = {0,};

_ftscanf(fp, _T("%d"), &num);

_ftscanf(fp, _T("%s"), szText);

_stscanf

sscanf

swscanf

문자열을 다른타입으로 바꿀때 주로 사용된다.

TCHAR szNum[] = _T("1234");

int num;

_stscanf(szNum_T("%d"), &num);

추가로 컴파일러에서 해당 함수들을 에러나 경고가 나타나는 경우가 있다.

대체로 printf 같은걸 printf_s로 쓰라는 메시지인듯하다.

 

이유는 내부적으로 버퍼 오버플로우가 발생할수 있기 때문이다.

 

대부분은 _s가 붙은 함수들이 이를 대체하고 있다.

해당함수(_s) 들은 대부분 버퍼사이즈만 추가하여 사용가능하기 때문에 따로 기재하지는 않겠다.

 

그리고 이 함수들을 그냥 쓰려면 전처리기에 _CRT_SECURE_NO_WARNINGS 를 추가하거나

#define로 선언해두면 에러나 경고는 사라지기는 한다. (안정성은 보장못함...)

 

 

2.       Formatted I/O

MACRO

ANSI

UNICODE

설명

_fgettc

fgetc

fgetwc

파일에서 문자 하나 읽어온다.    int fgetc(FILE* stream);

_fputtc

fputc

fputwc

파일에 문자 하나 기록한다.    int fputc(int character, FILE* stream);

_fgetts

fgets

fgetwc

파일에서 문자열을 읽어온다.    char* fgets(char* str, int num, FILE* stream);

num -1 만큼 문자열을 읽어온다. (마지막은 자동으로 NULL로 채워진다. 그래서 -1)

또는 EOF (end of file) 까지

 

FILE* fp = _tfopen(_T("filename"), _T("r"));

TCHAR szBuf[256] = {0,};
while( 0 != _fgetts(szBuf, 256, fp) ) // 실패 인경우 0리턴, EOF는 -1

{

    _tprintf("%s", szBuf);

}

fclose(fp); // fclose는 문자열입력이 없기때문에 유니코드가 따로없다.

_fputts

fputs

fputws

파일에 문자열을 기록한다.    int fputs(const char* str, FILE* stream);

FILE* fp = _tfopen(_T("filename"), _T("a"));
_fputts(_T("Hello world!!\n"), fp); 
fclose(fp);

_gettc

getc

getwc

문자하나를 파일, 콘솔(stdin)입력받는다.  int getc(FILE* stream);

_puttc

putc

putwc

문자하나를 파일, 콘솔(stdout)에 출력    int putc(int character, FILE* stream);

_gettchar

getchar

getwchar

문자하나를 콘솔로 입력받는다.  int getchar(void);

_puttchar

putchar

putwchar

문자하나를 콘솔로 출력한다.    int putchar(int character);

_getts

gets

_getws

문자열을 콘솔로 입력받는다.    char* gets(char* buffer);

_putts

puts

_putws

문자열을 콘솔로 출력한다.    int puts( const char *str );

_ungettc

ungetc

ungetwc

스트림에 문자를 다시 집어 넣는다(unget)    int ungetc(int character, FILE* stream);

 

fwrite

 

파일 쓰기

size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

 

FILE *fp = _tfopen(_T("filename.txt"), _T("w")); 

 

//  UniCode BOM 기록
WORD wMark = 0xFEFF; 
fwrite(&wMark, sizeof(WORD), 1, fp); 

_ftprintf(file, L"123 가나다"); 
fclose(fp);

 

fread

 

파일 읽기

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

 

FILE *fp = _tfopen(_T("filename.txt"), _T("r")); 

 

//  UniCode BOM 검사
WORD wMark = NULL;
fread(&mark, sizeof(WORD), 1, fp); 

if( 0xFEFF != wMark )

{

    fclose(fp);

    reutrn;

}

 

WCHAR szBuf[256] = {0,};

while(fread(szBuf, sizeof(WCHAR), 256-1, fp)) //  버퍼의 마지막포인터 NULL 유지

{

    _putts(szBuf);

}
fclose(fp);

추가로 파일 입출력관련해서 더 적었습니다.

 

 

비슷하지만 미묘한 차이 getch(), getchar()

https://kcoder.tistory.com/entry/getchar-getch-getche%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EC%98%88%EC%A0%9C%EC%86%8C%EC%8A%A4-%EA%B7%B8%EB%A6%BC 

 

getchar(), getch(), getche()의 차이점. 예제소스 & 그림

알듯 모를듯 한 미묘한 3가지 함수의 차이점에 대해서 파헤쳐 보자 -_-!! getchar(), getch(), getche()의 차이점 !! 비슷해 보이는 3가지 종류의 함수가 있다. 차이가 뭘까? 어떻게 보면 사실 결과는 같을 수도..

kcoder.tistory.com

 

 

3. 파일 오픈 함수

MACRO

ANSI

UNICODE

설명

_tfopen

 fopen

_wfopen

파일 열기

FILE* fp = _tfopen(_T("filename.txt"), _T("r"));

_tfreopen

 freopen

_wfreopen

파일 닫고 다시 열기(옵션전환용?)

FILE* fp = _tfopen(_T("filename.txt"), _T("r"), fp);

fopen 옵션 참고

r = 읽기/ w = 쓰기 / a = 추가

rb = 바이너리읽기/ rw = 바이너리쓰기/ ra = 바이너리추가

뒤에 b(바이너리)가 없을시 기본 t(텍스트)로 열게된다.

r+, w+, a+는 추가적으로 읽기쓰기가 모두 가능하다.

 

 

 

4. 문자열 변환 함수

MACRO

ANSI

UNICODE

설명

_tcstod

strtod

wcstod

버퍼에서 실수(double)를 추출한다 (string to Double)

TCHAR szText[] = _T("123.112asdasd");

TCHAR* pPos = nullptr;

double value = _tcstod(src, pPos); // 123.112

// pPos = szText[7]

_tcstol

strtol

wcstol

버퍼에서 정수를 추출 (+진법) (string to long)

TCHAR szText[] = _T("123.112asdasd");

int num1 = _tcstol(szText, nullptr, 10); // 123

_tcstoul

strtoul

wcstoul

버퍼에서 unsigned 정수를 추출 (string to unsigned long)

잘 사용하면 atoi 류 보다 나을수 있다.

_itot

_itoa

_itow

TCHAR _itot(int val, TCHAR* buf, int radix); // 정수를 문자열로

_ltot

_ltoa

_ltow

TCHAR ltot (long val, TCHAR* buf, int radix);

_ultot

_ultoa

_ultow

TCHAR _ultot (unsigned long val, TCHAR* buf, int radix);

_ttoi

atoi

_wtoi

int _ttoi (const TCHAR* str); // 문자열을 정수로

_ttoll

atoll

_wtoll

long long _ttoll (const TCHAR* str); // 문자열을 64정수로

 

5. String function

MACRO

ANSI

UNICODE

설명

_tcscat

strcat

wcscat

문자열 연결용    char *strcat(char *_Destination, char const *_Source);

 TCHAR szSrc[10] = _T("world");
TCHER szDec[20] = _T("Hello "); 

 

_tcscat(szDec, szSrc);    // szDec 뒤에 szSrc를 붙임

// szDec = Hello world

_tcschr

strchr

wcschr

문자 검색용    char *strchr(char * const _String, int const _Ch);

 TCHAR szTest = _T("Test abcd Text");

TCHAR* ptr = _tcschr(s1, 'a');  // 'a'로 시작하는 문자열 검색, 포인터 반환

// ptr == szTest[5]

_tcsrchr

strrchr

wcsrchr

strchr의 리버스 버전, 뒤에서부터 검색한다.

_tcscspn 

strcspn 

wcscspn 

strchr 의 배열버전, str1에 str2의 문자가 하나라도 포함되어 있는가?

size_t strcspn(const char* str1, const char* str2);

TCHAR szSrc[] = _T("Test Text");
TCHAR szCheckChar[] = _T("abcde");

size_t index = _tcscspn(szSrc, szCheckChar);    // index == 1
// Test Text의 'e'가 szCheckChar에 포함되어있는 첫번째 배열인덱스 1을 출력

_tcsspn 

strspn 

wcsspn 

strcspn의 반대, 포함되지 않은 첫번째 배열인덱스를 출력

_tcspbrk 

strpbrk 

wcspbrk 

strcspn의 포인터 버전, 포인터를 리턴한다.

_tcscmp

strcmp

wcscmp

문자열 비교용    int strcmp(const *_Str1, char const *_Str2);

 리턴값

-1: ASCII 코드 기준으로 문자열2(s2)가 클 때 
0: ASCII 코드 기준으로 두 문자열이 같을 때 
1: ASCII 코드 기준으로 문자열1(s1)이 클 때

 

TCHAR szTest[] = _T("Hello World!!");

int nRet = _tcscmp(_T("End Game"), szTest);

_tcsicmp

_stricmp

_wcsicmp

대소문자 구분없는 strcmp

_tcsncicmp

_tcsnicmp

_strnicmp

_wcsnicmp

strncmp에 추가로 비교할 문자열 길이를 제한할수있다.

_tcscpy

strcpy

wcscpy

char *strcpy(char *_Dest, char const *_Source); //  문자열 복사 return _Dest

_tcslen

strlen

wcslen

size_t strlen(const *_Str); // 문자열 길이반환 (널문자제외)

_tcsstr

strstr

wcsstr

 문자열 안에서 문자열 검색, 포인터 리턴

char *strstr(char * const _String, char const * const _SubString);

 

TCHAR szText[] = _T("Hello world!!");

TCHAR* pRet = _tcsstr(szText, _T("wor")); // wor으로 시작하는 문자열 검색

// pRet == szText[6]

_tcstok

strtok

wcstok

문자열 자르기 (원본 변형에 주의) char *strtok(char *_String, char const *_Delimiter);

TCHAR szText = _T("Apple, Melon, Grape");

TCHAR* pRet = _tcstok(szText, _T(", "));

// ", " 문자열을 널문자로 치환하고 문자열 포인터 리턴

// szText[5] = ',' -> '\0' 변경됨

 

while (pRet)
{
    _tprintf(_T("%s\n"), ptr);           // 문자열 출력
    pRet = _tcstok(nullptr, _T(", "));  // 다음 문자열로 이동 (대상 nullptr)

    // (주의) 내부변수 때문에 스레드 환경에서 문제 발생가능성 있음
}

 

[출력 예]

Apple

Melon

Grape

_tcsdup

_strdup

_wcsdup

문자열 복제, 메모리 할당(malloc)

TCHAR szBuf[256] = { 0, };
_tprintf(_T("input : "));
_getts(szBuf);

TCHAR* pCopy = _tcsdup(szBuf);
if (pCopy)
{
    _tprintf("%s malloc size :%d \n", pCopy, _tcslen(pCopy));
    free(pCopy);
}

_tcsset

_strset

_wcsset

문자열을 특정문자로 바꾸는 함수    char *_strset( char *string, int c ); 

TCHAR szTest = _T("Hello world!!\n");

_tcsset(szTest, '%');

 // Hello world!!\n -> %%%%%%%%%%%%%%

_tcsnset

_tcsncset

_strnset

_wcsnset

문자열을 특정문자로 바꾸는 함수 (+바꿀개수)

char *_strnset( char *string, int c , size_t count );

 

TCHAR szTest = _T("Hello world!!\n");

_tcsnset(szTest, '%', 3);

// Hello world!!\n -> %%%lo world!!\n

_tcsrev

_strrev

_wcsrev

 문자열 뒤집기    char *_strrev( char *string ); 

TCHAR szTest = _T("Hello world!!\n");

_tcsrev(szTest);

// Hello world!!\n -> \n!!dlrow olleH

_tcslwr

_strlwr

_wcslwr

 소문자로 변경    char *_strlwr( char *string ); 

TCHAR szTest = _T("Hello world!!\n");

_tcslwr(szTest);

// Hello world!!\n -> hello world!!\n

_tcsupr

_strupr

_wcsupr

대문자로 변경    char *_strupr( char *string );

TCHAR szTest = _T("Hello world!!\n");

_strupr(szTest);

// Hello world!!\n -> HELLO WORLD!!\n