책/제프리 리처의 WINDOWS VIA C, C++

WINDOWS VIA C/C++(31p ~ 41p): Chapter02 문자와 문자열로 작업하기

readme.md 2024. 1. 5. 00:17

제프리 리처의 WINDOWS VIA C/C++
https://www.yes24.com/Product/Goods/3205340
페이지 41p ~ 68p

41p ~ 68p

요약

  • Chapter02 문자와 문자열로 작업하기가 시작되는 부분이다.
  • 이 책에서는 유니코드와 안전 문자열 함수를 사용하고 있으며, 이는 애플리케이션의 지역화를 좀 더 쉽게 하고, COM이나 닷넷 프레임워크와의 상호운용에도 도움을 줄 수 있게 된다.

section01 문자 인코딩

  • 애플리케이션 지역화를 수행할 때 발생하는 전형적인 문제의 원인은 다양한 문자 집합 고려에 있다.
  • 윈도우는 유니코드 문자를 UTF-16으로 인코딩한다.
    • UTF-16은 각 문자를 2바이트로 구성한다.
    • 이 책에서 유니코드라고 하면 다른 언급이 없는 이상 UTF-16 인코딩을 의미한다.
  • 닷넷 프레임워크는 모든 문자와 문자열을 UTF-16으로 인코딩한다.

section02 ANSI 문자와 유니코드 문자 그리고 문자열 자료형

  • C언어의 char 자료형은 8비트의 ANSI 문자를 표현하기 위해 존재한다.
  • // 8비트 문자 char c = 'A';

// 99개의 8비트 문자 + 널문자
char szBuffer[100] = "A String";


- 최근의 마이크로소프트 C, C++ 컴파일러는 16비트 유니코드를 표현하기 위한 `wchar_t` 자료형을 내장 자료형으로 처리할 수 있는 기능이 추가되었다.
```cpp
// 16비트 문자
wchar_t c = L'A';

// 99개의 16비트 문자 + 널문자
wchar_t szBuffer[100] = L"A String";
  • 문자열 앞에 대문자 L은 컴파일러가 문자열을 유니코드로 다루도록 한다.
  • 컴파일러가 문자열을 데이터 섹션에 삽입할 때 UTF-16으로 인코딩된다.
    • 위의 코드에서는 모두 ASCII 문자이므로 남는 공간에 0이 삽입된다.

section03 윈도우 내의 유니코드 함수와 ANSI 함수

  • 윈도우 NT 이후의 모든 윈도우 버전은 유니코드를 바탕으로 작성되었다.
  • 창 생성, 텍스트 출력, 문자열 다루기 등 모든 핵심 함수들은 유니코드 문자열을 요구한다.
    • ANSI 문자열을 전달한다면, 이를 유니코드로 변경하고 운영체제에게 전달한다.
  • 윈도우는 문자열 인자를 가지는 함수를 제공하는 경우 일반적으로 동일한 함수를 두 가지 버전으로 제공한다.
  • // 유니코드 문자열 HWND WINAPI CreateWindowExW();

// ANSI 문자열
HWND WINAPI CreateWindoeExA();

// 일반적으로 사용하는 함수
// WinUser.h에 정의되어 유니코드 사용 여부에 따라 위의 함수 구분하여 호출
CreateWindowEx();

```

  • 앞서 말했듯이 윈도우는 ANSI 문자열을 전달하면 이를 유니코드로 변환하는 작업을 추가적으로 수행하기 때문에 CreateWindowExA를 호출하면 내부적으로 ANSI 문자열을 유니코드로 변경하고 CreateWindowExW를 호출한다.
  • 따라서 처음부터 유니코드를 사용하는 방향으로 애플리케이션을 개발하는 것이 좋다.

section04 C 런타임 라이브러리 내의 유니코드 함수와 ANSI 함수

  • C 런타임 라이브러리도 ANSI 문자와 유니코드 문자를 다루는 함수를 세트로 제공한다.
  • 다만 윈도우에서 제공하는 함수와는 다르게 ANSI 버전의 함수들도 정상적으로 작동하며, 내부적으로 유니코드 변환도 수행하지 않는다.

section05 C 런타임 라이브러리 내의 안전 문자열 함수

  • 문자열을 다루는 함수들은 항상 잠재적인 위험에 노출되어 있다.
  • strcpy, wcscpy 함수는 버퍼의 최대 크기를 인자로 받지 않기 때문에 메모리에 문제가 생겨도 에러를 보고받을 수 없고, 메모리가 정상적으로 운용되고 있는지 알 방법도 없다.
  • 안전한 코드를 작성하고 싶다면 C 런타임 라이브러리 내의 문자열 조작 함수는 더 이상 사용하지 않는 것이 좋다.
  • strlen, wcslen, _tcslen 등과 같이 전달된 문자열을 수정하지 않는 함수들은 사용해도 된다.
  • 그래도 좋은 방법은 StrSafe.h를 통해 새롭게 제공되는 안전 문자열 함수를 사용하는 것이다.

section06 왜 유니코드를 사용하는 것이 좋은가?

  • 다른 나라의 언어로 지역화하기 쉽다.
  • 단일의 바이너리 파일로 모든 언어를 지원할 수 있다.

section07 문자와 문자열 작업에 대한 권고사항

  • 문자열을 char 타입이나 byte의 배열로 생각하지 말고 문자의 배열로 생각
  • 문자나 문자열을 나타낼 때 중립 자료형(TCHAR/PTSTR)을 사용
  • 바이트나 바이트를 가리키는 포인터, 데이터 버퍼 등을 표현하기 위해서는 명시적인 자료형(BYTE, PBYTE)를 사용
  • 문자나 문자열 상수 값을 표현할 때에는 TEXT_T 매크로를 사용. 일관성과 가독성을 유지하기 위해 두 개의 매크로를 혼용해서는 안 된다.
  • 산술 계산 부분을 수정(바이트 단위가 아닌 문자 단위로 계산)
    • sizeof(szBuffer) -> _countof(szBuffer)_
    • malloc(chars) -> malloc(chars * sizeof(TCHAR): 메모리 할당은 바이트 단위로 수행
  • 문자열을 다루는 함수는 이름이 _s로 끝나거나 StringCch로 시작하는 안전 문자열 함수 사용
  • Kernel32가 제공하는 lstrcat, lstrcpy 등의 문자열 관련 함수 사용 금지
  • 문자열 비교는 다음과 같은 방법을 사용
    • 프로그램 내에서만 주로 사용하는 파일명, 경로명, XML 요소, 레지스트리 등: CompareStringOrdinal
      • 사용자의 언어 설정을 고려하지 않기 때문에 빠름
    • 사용자의 유저 인터페이스를 구성하는 문자열: CompareString(EX)
      • 문자열을 비교할 때 사용자의 언어 설정을 고려

section08 유니코드 문자열과 ANSI 문자열 사이의 변경

  • MultiByteToWideChar