[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 02. 아스키코드 vs 유니코드

2023. 9. 9. 18:26·독서/[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]

01. Windows에서의 유니코드(UNICODE)

먼저, 운영체제가 문자열을 표현하는 방법을 알아보자.

 

문자셋(Character Sets)의 종류와 특성

문자셋이란 문자들의 집합, 즉 “약속된 문자의 표현방법”을 말한다. 가장 대표적인 문자셋에는 아스키코드(ASCII CODE)와 유니코드(UNICODE)가 있다.

 

아스키코드

미국에서 정의하고 있는 표준으로, 알파벳과 몇몇 확장 문자를 포함하고 있다. 이는 256개를 넘지 않기 때문에 1바이트를 가지고 표현 가능하다. 따라서, 아스키코드는 1바이트로 표현된다.

 

유니코드

영어를 포함하여 다양한 언어들을 표현하고 있으며, 2바이트로 표현된다. 이는 표현할 수 있는 문자의 수가 65,536개가 되기 때문에 다양한 문자와 기호들을 표현할 수 있다.

 

이러한 문자셋들은 종류에 따라서 다음과 같이 세 가지 형태로 나뉜다.

 

[SBCS (Single Byte Character Set)]

이름에서 알 수 있듯이, Single Byte 즉, 1바이트 만을 사용하는 방식이며, 가장 대표적으로 아스키코드가 이에 해당한다.

 

[MBCS (Multi Byte Character Set)]

다양한 바이트 수를 사용하여 문자를 표현하는 방식으로, 어떤 문자는 1바이트로, 어떤 문자는 2바이트로 표현하게 된다. 이는 SBCS를 포함하고 있으며, 유니코드는 MBCS에 해당하지 않는다. 예시로, MBCS에서는 영어는 1바이트로, 한글은 2바이트로 처리된다.

 

[WBCS (Wide Byte Character Set)]

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

 

MBCS 기반의 문자열

아래의 코드를 통해 운영체제의 문자열 처리방식을 확인해 볼 수 있다. 

//MBCS1.cpp

#include <stdio.h>
#include <string.h>

int main(void)
{
	char str[] = "ABC한글"; //MBCS 기반 형식 확인
	int size = sizeof(str);
	int len = strlen(str);

	printf("배열의 크기: %d \n", size);
	printf("문자열 길이: %d \n", len);

	return 0;
}

 

실행결과:

배열의 크기: 8

문자열 길이: 7

 

ABC(3바이트) +한글(4바이트) + NULL(1바이트) = 8바이트 임을 알 수 있으며, 문자열 길이는 NULL 문자를 제외하여 7이 된다. 이를 통해 영어(1바이트), 한글(2바이트)로 처리하는 것을 알 수 있다. 즉, 현재 MBCS를 기반으로 코드가 실행됨을 알 수 있다.

 

또한, 아래와 같은 코드에서 MBCS 기반의 문제를 확인할 수 있다.

//MBCS2.cpp
#include <stdio.h>

int main(void)
{
	char str[] = "한글입니다";
	int i;

	for (int i = 0; i < 5; i++) //MBCS라 문자열 길이에 따른 반복문 X
		fputc(str[i], stdout);

	fputs("\n", stdout);

	for (i = 0; i < 10; i++)
		fputc(str[i], stdout);

	fputs("\n", stdout);
	return 0;
}

 

실행결과:

한글

한글입니다.

 

이러한 MBCS 기반 문자열은 위와 같은 경우에서 문제가 발생한다. 문자열 "한글입니다"는 길이가 5인 것처럼 보이지만, 이는 MBCS 기반의 문자열이기 때문에 5번째 문자까지 출력해도 정상적으로 출력되지 않는 것을 확인할 수 있다. 이러한 문제를 해결하기 위해 WBCS 방식을 이용한다.

 

WBCS 기반의 프로그래밍

WBCS 기반으로 프로그래밍을 위해 다음과 같은 것들을 이용할 것이다.

[char을 대신하는 wchar_t]

자료형 char를 대신해서 자료형 wchar_t를 사용해야 한다. char형 변수는 1바이트 메모리 공간만 할당되지만, wchar_t형 변수는 2바이트 메모리 공간이 할당되기 때문이다. 따라서 유니코드 기반으로 문자를 표현할 수 있다. 또한, 이는 다음과 같은 형태로 선언되어 있다.

 

typedef unsigned short wchar_t

 

[“ABC를 대신하는 L”ABC”]

자료형 wchar_t를 사용하여 다음과 같이 문자열을 선언할 경우, 문제가 발생한다.

 

wchar_t str[] = “ABC”;

 

배열 str은 유니코드 문자열을 저장할 준비가 되어있지만, 대입 연산자의 오른쪽에 존재하는 문자열은 여전히 MBCS 기반의 문자열이기 때문이다. 따라서 다음과 같이 선언해야 한다.

 

wchar_t str[] = L“ABC”;

 

 

문자열 앞에 선언된 문자 L은 “이어서 등장하는 문자열을 유니코드 기반으로 표현하라”는 의미를 지닌다. 따라서 이 경우에는 문자열 “ABC”는 NULL문자를 포함해서 총 8바이트로 표현된다.

 

[strlen을 대신하는 wcslen]

문자열의 길이를 확인하는 strlen 함수는 SBCS 기반 문자열을 위한 함수이다. 따라서 유니코드 기반의 문자열 처리를 위해 wcslen 함수를 사용하게 된다.

 

완전한 유니코드 기반으로 :

Windows 2000 이상의 운영체제는 기본적으로 유니코드를 지원하고, 내부적으로 모든 문자열을 유니코드 기반으로 처리한다. 따라서, 코드를 다음과 같이 SBCS 기반 문자열을 처리하도록 작성한다면, 내부적으로 문자열을 2바이트 유니코드 형식으로 변환한다.

printf(“Hello world!”);

 

이는 문자열셋을 변환하는 과정을 거치기 때문에 성능에 다소 영향을 미칠 수 있다. 따라서, 이를 다음과 같이 유니코드 기반의 프로그램을 작성한다면 성능에는 영향을 미치지 않는다.

wprintf(L“Hello world!”);

 

이외에도 .exe 파일을 생성하여 main함수에서 인자를 받을 때 유니코드 형식으로 받기 위해 wmain을 사용한다.


02. MBCS와 WBCS의 동시 지원

프로그램 구현 과정에서 MBCS 기반이나 WBCS 기반 어느 한쪽으로만 구현한다면, 나중에 다른 쪽으로 변경하기 위해 문자열 앞에 L을 붙이는 등 코드를 수정해야 할 것이다. 따라서, 프로그램을 한 번에 두 가지 기반 모두 컴파일 가능하도록 만들 것이다.

 

#include<windows.h>

windows.h는 Windows 기반 프로그래밍을 하는 데 있어서 기본적으로 항상 포함해야 하는 헤더이다. 이는 Windows 프로그래밍에 필요한 다양한 종류의 헤더 파일을 더불어 포함하기 때문에 대부분의 경우 이 헤더파일 하나로 충분하다.

 

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

Windows에서는 typedef 키워드를 이용해 몇몇 기본 자료형에 Windows 스타일의 새로운 이름을 다음과 같이 정의하고 있다.

typedef char CHAR
typedef wchar_t WCHAR

#define CONST const

typedef CHAR * LPSTR
typedef CONST CHAR * LPCSTR

typedef WCHAR * LPWSTR
typedef CONST WCHAR * LPCWSTR

 

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

Windows에서는 MBCS와 WBCS를 동시에 수용하는 형태의 프로그램 구현을 위해서 tchar.h 헤더 파일을 통해 매크로 상수 UNICODE와 _UNICODE를 이용해 다양한 자료형 및 매크로 함수를 다음과 같이 정의하고 있다.

//windows.h 포함 정의
#ifdef UNICODE
    typedef WCHAR TCHAR;
    typedef LPWSTR LPTSTR;
    typedef LPCWSTR LPCTSTR;
#else
    typedef CHAR TCHAR;
    typedef LPSTR LPTSTR;
    typedef LPCSTR LPCTSTR;
#endif

//tchar.h 포함 정의
#include <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)

이는 windows.h 헤더 파일에 포함되어 있지 않기 때문에, 따로 tchar.h 헤더파일을 추가해야 한다. 이를 이용하여 다음과 같은 MBCS와 WBCS(유니코드)를 동시에 지원하는 프로그램을 작성할 수 있다.

 

#define UNICODE //#include <tchar.h> 선언 전에 정의해야함
#define _UNICODE

//#undef UNICODE //#undef를 통해 MBCS 기반으로 컴파일 
//#undef _UNICODE

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

int main(void)
{
    TCHAR str[] = _T("1234567");
    int size = sizeof(str);
    printf("string length : %d \n", size);
    return 0;
}

 

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

Windows에서는 MBCS와 WBCS를 동시에 수용하는 형태의 프로그램 구현을 위해 매크로를 이용한 정의뿐만 아니라, 다음과 같은 함수들도 지원하고 있다.

#include <tchar.h>
#ifdef UNICODE
    #define _tmain wmain
    #define _tprintf wprintf
    ...
#else
    #define _tmain main
    #define _tprintf printf
    ...
#endif

이는 마찬가지로, tchar.h 헤더파일을 추가해야 한다.

 

다음은 최종적으로 지금까지 다루었던 내용을 한 번에 확인할 수 있는 예제이다.

//MBCS_WBCS2.cpp
#define UNICODE
#define _UNICODE
#define _CRT_SECURE_NO_WARNINGS //scanf 에러 무시

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

int _tmain(int argc, TCHAR* argv[])
{
	LPCTSTR 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


참고 자료:

윤성우. 『뇌를 자극하는 윈도우즈 시스템 프로그래밍』.한빛미디어, 2007.

'독서 > [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]' 카테고리의 다른 글

[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 06. 커널 오브젝트와 오브젝트 핸들  (2) 2023.09.24
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 05. 프로세스의 생성과 소멸  (1) 2023.09.17
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 04. 컴퓨터 구조에 대한 두 번째 이야기  (1) 2023.09.16
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 03. 64비트 기반 프로그래밍  (1) 2023.09.10
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 01. 컴퓨터 구조에 대한 첫 번째 이야기  (1) 2023.09.09
'독서/[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]' 카테고리의 다른 글
  • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 05. 프로세스의 생성과 소멸
  • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 04. 컴퓨터 구조에 대한 두 번째 이야기
  • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 03. 64비트 기반 프로그래밍
  • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 01. 컴퓨터 구조에 대한 첫 번째 이야기
coding-l7
coding-l7
  • coding-l7
    coding-l7rl0
    coding-l7
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 기타
      • 유니티
        • OfficeWorkerRunning
      • 프로그래밍 언어
        • C
        • C#
        • C++
      • CS
        • 컴퓨터 구조
        • 운영체제
      • 물리 기반 시뮬레이션
        • 기초
        • Cloth Simulation
        • Fluid Simulation
      • 코딩 테스트
        • 프로그래머스
        • 백준
      • 독서
        • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]
        • [ 혼자 공부하는 컴퓨터 구조 + 운영체제 ]
        • [ CUDA 기반 GPU 병렬 처리 프로그래밍 ]
      • 영어
        • Basic Grammar In Use
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
    • 포트폴리오
  • 공지사항

  • 인기 글

  • 태그

    cloth simulation
    narrow range filter screen-space fluid rendering
    그리드 기반 방법
    surface turbulence
    상수
    OpenGL
    C언어
    jump table
    GLSL
    유체 시뮬레이션
    입자 기반 방법
    bilateral blur
    시스템 프로그래밍
    실수
    pbd
    물리 기반 시뮬레이션
    position based dynamics
    fluid simulation
    screen space fluid rendering
    명령어
    파동 난류
    정수 승격
    screen-space rendering
    Flip
    컴퓨터 구조
    collision
    fluid implicit particle
    RAM
    wave simulation
    액체 시뮬레이션
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
coding-l7
[ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ] Chapter 02. 아스키코드 vs 유니코드
글쓰기
상단으로

티스토리툴바