Windows에서의 유니코드(UNICODE)

1. 문자셋의 종류와 특성

- 아스키코드(ASCII): 미국에서 정의하고 있는 표준, 1바이트로 표현(256개까지 표현 가능)

- 유니코드(UNICODE):  문자를 균일하게 2바이트로 표현(65,536개 표현 가능)

- 문자셋: 문자들의 집합, 약속된 문자의 표현 방법


1) SBCS(Single Byte Character Set)

- 1바이트로 문자 표현

- 아스키 코드가 대표적으로 포함


2) MBCS(Multi Byte Character Set)

- DBCS(Double Byte Character Set)이라고도 함

- 문자를 표현 하는데 있어서 동일한 바이트 수를 적용하는 것이 아니라 다양한 바이트 수를 적용해서 문자를 표현

- 유니코드는 MBCS에 속하지 않음

- 영어는 1바이트, 한글은 2바이트로 처리됨

- 프로그램을 구현하는 데 있어서 주의 요함


3) WBCS(Wide Byte Character Set)

- 모든 문자를 2바이트로 처리

- 유니코드가 대표적으로 포함


2. MBCS 기반의 문자열

1) MBCS 예제

#include <stdio.h>

#include <string.h>


int main(void)

{

char str[] = "ABC한글";

int size = sizeof(str);

int len = strlen(str);


printf("배열의크기: %d \n"size);

printf("문자열의크기: %d \n"len);


return 0;

}

배열의 크기: 8

문자열의 크기: 7

- 영문은 1바이트, 한글은 2바이트로 처리되고 있음

- strlen은 문자열의 길이를 계산함에 있어서 NULL문자를 포함하지 않음

2) MBCS 예제 2

#include <stdio.h>


int main(void)

{

char str[] = "한글입니다";

int i;


for(i=0; i<5; i++)

fputc(str[i], stdout);


fputs("\n"stdout);


for(i=0; i<10; i++)

fputc(str[i], stdout);


fputs("\n"stdout);


return 0;

}

한글

한글입니다


3) MBCS의 문제점, 해결책 제시

- 영어는 1바이트, 한글은 2바이트로 처리

- 문자의 출력, 처리 프로그래밍에 있어서 주의를 기울여야 함

- MBCS의 문제점을 해결할 수 있는 것이 WBCS방식

- WBCS 방식은 모든 문자들을 2바이트로 처리, 모든 문자들을 동일한 바이트의 크기로 처리함


3. WBCS 기반의 프로그래밍

1) char를 대신하는 wchar_t

- char형 변수: 1바이트 메모리 공간만 할당

- wchar_t형 변수: 2바이트 메모리 공간이 할당, 유니코드 기반으로 문자를 표현하는 것이 가능

typedef unsigned short wchar_t;


2) "ABC"를 대신하는 L"ABC"

wchar_t str[] = L"ABC";

- 문자 L: 이어서 등장하는 문자열을 유니코드 기반(WBCS 기반)으로 표현, 각문자는 2바이트로 표현

- 유니코드에서는 문자열 끝을 의미하는 널문자도 2바이트로 처리


3) strlen을 대신하는 wcslen

#include <stdio.h>

#include <string.h>


int main(void)

{

wchar_t str[] = L"ABC";

int size = sizeof(str);

int len = strlen(str);


printf("배열의크기: %d \n"size);

printf("문자열길이: %d \n"len);


return 0;

}

1>c:\users\xxx\desktop\mbcs\mbcs\mbcs.cpp(27) : error C2664: 'strlen' : cannot convert parameter 1 from 'wchar_t [4]' to 'const char *'

1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

1>MBCS - 1 error(s), 0 warning(s)

- strlen 함수는 SBCS 기반(아스키코드 기반)문자열을 처리하기 위한 함수

strlen (const char * str)

- sizeof는 연산자: 배열에 어떠한 문자열이 저장되어 있건 상관없이 배열의 크기를 계산해서 반환


4) 문자열 조작 함수

 SBCS, MBCS 기반 문자열 조작 함수

 WBCS 기반의 문자열 조작 함수

 strlen

 size_t wcslen(const wchar_t* string)

 strcpy

 wchar_t* wcscpy(wchar_t* dest, const wchar_t* src)

 strncpy

 wchar_t* wcsncpy(wchar_t* dest, const wchar_t* src, size_t cnt)

 strcat

 wchar_t* wcscat(wchar_t* dest, const wchar_t* src)

 strncat

 wchar_t* wcsncat(wchar_t* dest, const wchar_t* src, size_t cnt)

 strcmp

 int wcscmp(const wchar_t* s1, const wchar_t* s2)

 strncmp

 int wcsncmp(const wchar_t* s1, const wchar_t* s2, size_t cnt)

- WBCS 기반 함수의 전달인자는 유니코드 기반 문자열

- size_t

typedef unsigned int size_t;


5) WBCS 예제

#include <stdio.h>

#include <string.h>


int main(void)

{

wchar_t str[] = L"ABC";

int size = sizeof(str);

int len = wcslen(str);


printf("배열의크기: %d \n"size);

printf("문자열의길이: %d \n"len);


return 0;

}

배열의 크기: 8

문자열의 길이: 3


6) 완전한 유니코드 기반으로 변환 1

- windows 2k 이상의 운영체제는 기본적으로 유니코드 지원

- windows 2k 이상의 운영체제에서 SBCS 방식 문자열 조작 함수 호출이 이루어 진다면 운영체제는 전달되는 문자열을 내부적으로 2바이트 유니코드 형식으로 변환, 성능에 영향을 미침

 SBCS 함수

 WBCS 기반의 문자열 입,출력 함수

 printf

 int wprintf(const wchar_t* format[,argument]...)

 scan

 int wscanf(const wchar_t* format [,argument]...)

 fgets

 wchar_t* fgetws(wchar_t* string, int n, FILE* stream)

 fputs

 int fputws(const wchar_t* string, FILE* stream)

#include <stdio.h>

#include <string.h>


int main(void)

{

wchar_t str[] = L"ABC";

int size = sizeof(str);

int len = wcslen(str);


wprintf(L"Array Size: %d \n"size);

wprintf(L"String Length: %d \n"len);


return 0;

}

Array Size: 8

String Length: 3


* wprintf, fputws  같은 함수들을 통해 유니코드 기반으로 한글을 출력

wprintf, fputws 함수전에 아래 함수가 호출되어야 함

- _wsetlocale 함수: 프로그램이 실행되는 나라 및 지역에 대한 정보를 설정하는 함수

_wsetlocale(LC_ALLL"korean"); //#include "locale.h"


7) 완전한 유니코드 기반으로 변환 2

- 실행인자를 출력하는 코드

#include <stdio.h>


int main(int argccharargv[])

{

int i;


for(i=0; i<argci++)

fputws(argv[i], stdout);


return 0;

}

1>c:\users\xxx\documents\visual studio 2008\projects\wbcs3\wbcs3\wbcs3.cpp(8) : error C2664: 'fputws' : cannot convert parameter 1 from 'char *' to 'const wchar_t *'

1>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

1>WBCS3 - 1 error(s), 0 warning(s)

- char* argv[]를 wchar_t* argv[]로 변경하면 컴파일 에러는 발생하지 않지만 결과 출력이 안됨

- main 함수는 프로그램 실행시 전달되는 문자열을 MBCS 기반으로 구성하기 때문


8) 프로그램 실행시 전달되는 문자열을 유니코드 기반으로 구성하기 위한 main 함수

- wmain 함수에 대한 이해

- wmain 함수: 프로그램 실행시 전달되는 문자열을 유니코드 기반으로 구성

- 프로그램 실행시 추가로 문자열 AAA BBB CCC를 전달했을때 실행 결과 코드

#include <stdio.h>


int wmain(int argcwchar_targv[])

{

for(int i=1; i<argci++)

{

fputws(argv[i], stdout);

fputws(L"\n"stdout);

}


return 0;

}

AAA

BBB

CCC


<참고 - visual studio 2008에서 실행 인자 지정 방법>


MBCS와 WBCS의 동시 지원

- 현존하는 시스템 모두가 완벽히 유니코드 기반을 지원하는 것이 아니므로 프로그램을 MBCS나 WBCS 기반으로 구현할 지 결정하는데에 어려움이 있음

- 프로그램은 한번만 구현하고 별다른 변경없이 MBCS와 WBCS 기반으로 실행되는 형태로 컴파일이 가능하기 위한 방법이 필요


1. #include <windows.h>

- windows.h: windows 기반 프로그래밍을 하는데 있어서 기본적으로 항상 포함 해야 하는 헤더 파일


2. windows에서 정의하고 있는 자료형

1) CHAR, WCHAR

- windows.h를 통해서 정의

typedef char CHAR;

typedef wchar_t WCHAR;


2) 문자열의 주소값을 저장할 수 있는 Windows 스타일의 자료형 정의

- windows 스타일의 자료형이 대문자로 구성

#define CONST    const

typedef  CHAR *     LPSTR;

typedef  CONST CHAR *    LPCSTR;



typedef  WCHAR *    LPWSTR;


typedef  CONST WCHAR *    LPCWSTR;


#include <stdio.h>

#include <windows.h>


int wmain(int argcwchar_targv[])

{

LPSTR str1 = "SBCS Style String 1";

LPWSTR str2 = L"WBCS Style String 1";


CHAR arr1[] = "SBCS Style String 2";

WCHAR arr2[] = L"WBCS Style String 2";


LPCSTR cStr1 = arr1;

LPCWSTR cStr2 = arr2;


printf("%s \n"str1);

printf("%s \n"arr1);


wprintf(L"%s \n"str2);

wprintf(L"%s \n"arr2);


return 0;

}

SBCS Style String 1

SBCS Style String 2

WBCS Style String 1

WBCS Style String 2


*typedef를 이용한 Windows 스타일 자료형 정의

- 선언의 편리성

- 확장의 용이성


3. MBCS와 WBCS를 동시 지원하기 위한 매크로

1) MBCS와 WBCS를 동시에 수용하는 형태의 프로그램 구현을 위한 매크로

- windows에 선언되어 있는 것을 간략화 한 것

#ifdef UNICODE

typedef WCHAR TCHAR;

typedef LPWSTR LPTSTR;

typedef LPCWSTR LPCTSTR;

#else

typedef CHAR TCHAR;

typedef LPSTR LPTSTR;

typedef LPCSTR LPCTSTR;

#endif

- tchar.h에 선언되어 있는 내용을 편집해 놓은것

- windows.h에 tchar.h가 포함되어 있지 않으므로 추가로 포함 시켜야 됨


#ifdef _UNICODE

#define __T(x) L ## x

#else

#define __T(x) x

#endif


#define _T(x) __T(x)

#define _TEXT(x) __T(x)

a. 유니코드와 MBCS를 동시 지원하는 프로그램의 예

#define UNICODE

#define _UNICODE


#include <stdio.h>

#include <tchar.h>

#include <Windows.h>


int wmain(void)

{

TCHAR str[] = _T("1234567");

int size = sizeof(str);

printf("string length: %d \n", size);


return 0;

}

string length: 16

b. 유니코드 define문을 주석처리 하고 실행

- 예상 출력값 8, 실제 출력값과 차이가 있음

- Winodws xp이상의 시스템에서 .NET 컴파일러 버전 2005 이상을 사용하는 경우 발생할 수 있음

//#define UNICODE

//#define _UNICODE


#include <stdio.h>

#include <tchar.h>

#include <Windows.h>


int wmain(void)

{

TCHAR str[] = _T("1234567");

int size = sizeof(str);

printf("string length: %d \n", size);


return 0;

}

string length: 16

- 이유: visual studio에 미리 정의 되어 있기 때문..


- 주석처리를 하지 않았을때 warning 발생

1>c:\users\xxx\documents\visual studio 2008\projects\mbcs_wbcs1\mbcs_wbcs1\mbcs_wbcs1.cpp(1) : warning C4005: 'UNICODE' : macro redefinition

1>        command-line arguments :  see previous definition of 'UNICODE'

1>c:\users\xxx\documents\visual studio 2008\projects\mbcs_wbcs1\mbcs_wbcs1\mbcs_wbcs1.cpp(2) : warning C4005: '_UNICODE' : macro redefinition

1>        command-line arguments :  see previous definition of '_UNICODE'


2) MBCS 기반으로 컴파일 하는 방법

a. 설정창에서 UNICODE, _UNICODE 를 지움 - Inherit from parent or project defaults 체크박스 해제

b. #undef 지시자를 통해 설정 값을 지움

#undef _UNICODE

#undef UNICODE


#include <stdio.h>

#include <tchar.h>

#include <Windows.h>

...


4. MBCS와 WBCS를 동시 지원하기 위한 함수들

#define  UNICODE

#define _UNICODE


#include <stdio.h>

#include <tchar.h>

#include <Windows.h>


int _tmain(int argc, TCHAR* argv[])

{

LPTSTR str1 = _T("MBCS or WBCS 1");

TCHAR str2[] = _T("MBCS or WBCS 2");

TCHAR str3[100];

TCHAR str4[50];


LPCTSTR pStr = str1;


_tprintf(_T("string size: %d \n"), sizeof(str2));

_tprintf(_T("string length: %d \n"), _tcslen(pStr));


_fputts(_T("Input String 1: "), stdout);

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

_fputts(_T("Input String 2: "), stdout);

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


_tcscat(str3, str4);

_tprintf(_T("String1 + String2: %s \n"), str3);


return 0;

}

string size: 30

string length: 14

Input String 1: Hello

Input String 2: World

String1 + String2: HelloWorld