CAFE

Visual C++ - MFC

아스키코드 VS 유니코드, strcpy wcsncpy

작성자정기순|작성시간08.07.10|조회수942 목록 댓글 1

 

http://joyholic.kr/158

 

문자셋의 종류와 특성

가장 대표적인 문자셋에 해당하는 아스키코드(ASCII CODE)와 유니코드(UNICODE)에 대해서

간단히 언급하고자 한다. 아스키코드는 미국에서 정의하고 있는 표준이다. 알파벳의 개수는

26개이다. 여기다가 몇몇 확장 문자를 포함해도 총 256개를 넘지 않는다. 그래서 1바이트를

가지고도 충분히 표현할 수 있다. 다시 말해서 아스키코드는 1바이트로 표현이 된다.

문제는 영어가 아닌 다른 국가에서 사용하는 문자들을 표현하는 일이다. 우리나라를 예로 들어

보자. 컴퓨터에 한글을 인식시키기 위해서는 글자 하나하나마다 값(숫자)을 지정해 줘야만 한다.

아스키코드처럼 말이다. 그렇다고 해서 미국에서 영어를 표현하기 위해 정의해 놓은 아스키코드값을

한글로 표현하는 데에 사용할 수도 없는 일이다. 그래서 등장한 것이 유니코드이다.

유니코드는 문자열을 표현하는데 있어서 균일하게 2바이트를 사용한다. 2바이트면 나타낼 수 있는

문자의 종류가 65,536개에 이른다. 이 정도면, 영어와 한글은 물론이거니와 전세계의 거의 모든

문자와 다양한 종류의 기호를 표현할 수가 있다.

그럼 이제 문자셋(Set)에 대해 조금 더 구체적으로 들어가 보겠다. 문자셋이란 문자들의 집합,

다시 말해서 "약속된 문자의 표현방법" 을 의미한다. 문자셋은 그 종류에 따라서 다음과 같이 크게

세 가지 형태로 나뉘어진다.


 

[SBCS(Single Byte Character Set)]

문자를 표현하는데 있어서 1바이트만을 사용하는 방식이다. 우리에게 가장 익숙한 아스키 코드가

대표적인 SBCS에 해당된다.


 

[MBCS(Multi Byte Character Set)]

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

문자를 표현하는 방식이다. 아스키코드에서 정의하고 있는 문자를 표현할 때에는 1바이트로 처리하고,

아스키코드에서 정의하지 않은 다른 문자를 표현할때에만 2바이트로 처리하는 방식이다. 모든 문자를

2바이트로 처리하는 유니코드와 비교하면 상당히 효율적으로 문자를 표현한다는 느낌을 받을 수 있다.

그러나 그 만큼 프로그램을 구현하는 데 있어서 세심한 주의를 기울여야 한다.


 

[WBCS(Wide Byte Character Set)]

모든 문자를 2바이트로 처리하는 문자셋이다. 유니코드가 WBCS방식에 해당한다.


 

- WBCS 기반의 프로그래밍 -

WBCS 기반(유니코드 기반)으로 프로그래밍을 하기 위해서는 몇 가지 신경 쓸 일이 있다.

[char을 대신하는 wchar_t]

문자를 표현하는 데 사용되는 자료형 char를 대신해서 자료형 wchar_t를 사용해야 한다. char형

변수는 1바이트 메모리 공간만 할당되지만, wchar_t형 변수는 2바이트 메모리 공간이 할당된다.

wchar_t은 다음과 같은 형태로 선언되어 있는 자료형이다.

typedef unsigned short wchar_t;

["ABC"를 대신하는 L"ABC"]

다음은 자료형 wchar_t를 이용한 문자열의 선언을 보여준다.

wchar_t str[] = "ABC";

만약에 이러한 형태로 문자열을 선언한다면 문제가 발생한다. 왜냐하면 배열 str은 유니코드 문자열을

저장할 준비가 되어 있음에도 불구하고, 대입 연산자의 오른쪽에 존재하는 문자열은 여전히 MBCS 기반

문자열이기 때문이다. 그러므로 이 문자을 다음과 같은 형태로 변경해야 한다.

wchar_t str[] = L"ABC";

문자열 앞에 선언된 문자 L은 "이어서 등장하는 문자열을 유니코드 기반(WBCS 기반)으로 표현하라" 는

의미를 지닌다. 따라서 이 경우에는 문자열 "ABC"는 널(NULL)문자를 포함해서 총 8바이트로 표현된다.

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

다음 표는 SBCS 기반 문자열 조작 함수와, 이에 대응하는 WBCS 기반 문자열 조작 함수를 정리해서

보여준다.

 SBCS 함수  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);

완전한 유니코드 기반으로

Windows 2000 이상의 운영체제는 기본적으로 유니코드를 지원할 뿐만 아니라 내부적으로 모든 문자열을

유니코드 기반으로 처리한다. SBSC 기반으로 문자열을 처리하면 운영체제는 전달되는 문자열을 내부적

으로 유니코드 형식으로 변환한다. 이는 프로그램 성능에 다소 영향을 미치는 요소가 될 수 있다.

 SBCS 함수  WBCS 기반의 문자열 입 * 출력 함수
 printf  int wprintf(const wchar_t* format [, argument]...);
 scanf  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);

MBCS와 WBCS의 동시 지원

프로그램 구현에 있어서 MBCS 기반으로 할 것이냐, 아니면 WBCS 기반으로 할 것이냐를 결정짓는 일은

골치 아픈 일이 아닐 수 없다. 물론 WBCS 기반으로 구현하는 것이 여러모로 좋을 듯 하나, 아직까지 현존

하는 시스템 모두가 완벽히 유니코드를 기반을 지원하는 것이 아니기 때문에 문제가 발생할 소지가 높다.

프로그램은 한번만 구현하고, 별다른 변경없이 MBCS 기반으로 돌아가는 형태로도, WBCS 기반으로

돌아가는 형태로도 컴파일 가능하다면 아주 만족스러울 것이다. 이제 그 방법을 소개하고자 한다.


 

- Windows에서 정의하고 있는 자료형 -

Windows에서는 typedef 키워드를 통하여 몇몇 기본 자료형에 Windows 스타일의 새로운 이름을 정의하고

있다. 다음은 Windows 스타일의 자료형 CHAR와 WCHAR가 어떻게 정의되어 있는지를 보여준다. 물론

Windows.h에 정의되어 있다.

typedef char CHAR;

typedef wchar_t WCHAR;

다음은 문자열의 주소값을 저장할 수 있는 Windows 스타일의 자료형이 어떻게 정의되어 있는지를 보여준다.

#define CONST const


 

typedef CHAR* LPSTR;

typedef CONST CHAR* LPCSTR;


 

typedef WCHAR* LPWSTR;

typedef CONST WCHAR* LPCWSTR;


 

- MBCS와 WBCS(유니코드)를 동시에 지원하기 위한 매크로 -

Windows에서는 MBCS와 WBCS를 동시에 수용하는 형태의 프로그램 구현을 위해서 매크로를 정의하고 있다.

다음은 Windows에 선언되어 있는 내용을 보기 좋은 구조로 간략화한 것이다.

#ifdef UNICODE

 typedef WCHAR         TCHAR;

 typedef LPWSTR        LPTSTR;

 typedef LPCWSTR      LPCTSTR;

#else

 typedef CHAR            TCHAR;

 typedef LPSTR           LPTSTR;

 typedef LPCTSTR       LPCTSTR;

#endif


 

#ifdef _UNICODE

 #define __T(x) L ## x

#else

 #define __T(x) x

#endif


 

#define _T(x)         __T(x)

#define _TEXT(x)   __T(x)


 

매크로 UINCODE가 정의되어 있다면

TCHAR arr[10]; --> WCHAR arr[10]; --> wchar_t arr[10];

매크로 UINCODE가 정의되어 있지 않다면

TCHAR arr[10]; --> CHAR arr[10]; --> char arr[10];


 

매크로 _UNICODE가 정의되어 있다면

_T("TEST"); --> __T("TEST"); --> L"TEST"

매크로 _UNICODE가 정의되어 있지 않다면

_T("TEST"); --> __T("TEST"); --> "TEST"


 

- MBCS와 WBCS(유니코드)를 동시에 지원하기 위한 함수들 -

다음은 tchar.h에 선언되어 있는 함수 이름과 관련된 매크로이다.

#ifdef _UNICODE

 #define _tmain      wmain

 #define _tcslen     wcslen

 #define _tcscat     wcscat

 #define _tcscpy    wcscpy

 #define _tcsncpy  wcsncpy

 #define _tcscmp   wcscmp

 #define _tcsncmp  wcsncmp

 #define _tprintf      wprintf

 #define _tscanf     wscanf

 #define _fgetts      fgetws

 #define _fputts      fputws

#else

 #define _tmain      main

 #define _tcslen     strlen

 #define _tcscat     strcat

 #define _tcscpy    strcpy

 #define _tcsncpy  strncpy

 #define _tcscmp   strcmp

 #define _tcsncmp  strncmp

 #define _tprintf      printf

 #define _tscanf     scanf

 #define _fgetts      fgets

 #define _fputts      fputs

#endif


 

#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;

}

main조차도 _tmain으로 선언되어 있다. 따라서 매크로 _UNICODE의 선언에 따라 MBCS 기반의

main이 될 수도 있고, 유니코드 기반의 wmain이 될수도 있다.

 

[]

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
  • 작성자정창욱 | 작성시간 08.07.11 윈도우 프로그래밍에서는 이부분이 중요하더라구요~ 사소한 에러도 많이 나고 ㅋㅋ
댓글 전체보기
맨위로

카페 검색

카페 검색어 입력폼