C ++ wchar_t 및 wstrings에서 "잘못된"것은 무엇입니까? 와이드 문자의 대안은 무엇입니까?


87

나는의 사용을 원망는 C ++ 커뮤니티 (는 Freenode에 특히 ## C ++)에서 많은 사람들을 보았다 wstrings하고 wchar_t, 그리고 윈도우 API에서의 사용. wchar_twstring에서 정확히 "잘못된"것은 무엇이며 국제화를 지원하려는 경우 와이드 문자에 대한 몇 가지 대안은 무엇입니까?


1
그것에 대한 참조가 있습니까?
Dani

14
이 멋진 스레드가 모든 질문에 답할 수 있을까요? stackoverflow.com/questions/402283/stdwstring-vs-stdstring
MrFox

15
Windows에서는 선택의 여지가 없습니다. 내부 API는 UCS-2 용으로 설계되었는데, 이는 가변 길이 UTF-8 및 UTF-16 인코딩이 표준화되기 전 이었기 때문에 당시에는 합리적이었습니다. 그러나 이제 UTF-16을 지원하므로 두 세계 모두에서 최악의 결과를 낳았습니다.
jamesdlin

12
utf8everywhere.org 에는 와이드 문자를 피해야하는 이유에 대한 좋은 토론이 있습니다.
JoeG 2012-06-20

5
@jamesdlin 확실히 당신은 선택권이 있습니다. nowide 라이브러리는 API에 전달할 때 문자열을 변환하는 편리한 방법을 제공합니다. 문자열을 사용한 API 호출은 일반적으로 빈도가 낮으므로 합리적인 방법은 ad-hok로 변환하고 항상 파일 및 내부 변수를 UTF-8로 유지하는 것입니다.
Pavel Radzivilovsky

답변:


115

wchar_t는 무엇입니까?

wchar_t는 모든 로케일의 char 인코딩이 모든 wchar_t가 정확히 하나의 코드 포인트를 나타내는 wchar_t 표현으로 변환 될 수 있도록 정의됩니다.

wchar_t 유형은 값이 지원되는 로케일 (22.3.1) 중 지정된 가장 큰 확장 문자 세트의 모든 멤버에 대한 고유 코드를 나타낼 수있는 고유 한 유형입니다.

                                                                               — C ++ [basic.fundamental] 3.9.1 / 5

이것은 wchar_t가 모든 로케일의 모든 문자를 동시에 나타낼 수있을만큼 충분히 커야 할 필요 는 없습니다 . 즉, wchar_t에 사용되는 인코딩은 로케일마다 다를 수 있습니다. 즉, 한 로케일을 사용하여 반드시 문자열을 wchar_t로 변환 한 다음 다른 로케일을 사용하여 char로 다시 변환 할 수는 없습니다. 1

모든 로케일 간의 공통 표현으로 wchar_t를 사용하는 것이 실제로 wchar_t의 주요 용도 인 것처럼 보이므로 그렇지 않은 경우 무엇이 좋은지 궁금 할 것입니다.

wchar_t의 원래 의도와 목적은 문자열의 코드 단위에서 텍스트의 문자로의 일대일 매핑이 필요하도록 정의하여 텍스트 처리를 단순화하여 사용 된 것과 동일한 간단한 알고리즘을 사용할 수 있도록하는 것이 었습니다. ASCII 문자열로 다른 언어와 함께 작동합니다.

불행히도 wchar_t 사양의 문구는이를 달성하기 위해 문자와 코드 포인트 간의 일대일 매핑을 가정합니다. 유니 코드는 가정 2를 깨뜨 리므로 간단한 텍스트 알고리즘에도 wchar_t를 안전하게 사용할 수 없습니다.

즉, 휴대용 소프트웨어는 wchar_t를 로케일 간의 텍스트에 대한 공통 표현으로 사용하거나 간단한 텍스트 알고리즘을 사용할 수 없음을 의미합니다.

오늘날 wchar_t는 어떤 용도로 사용됩니까?

어쨌든 이식 가능한 코드는 많지 않습니다. __STDC_ISO_10646__이 정의 되면 wchar_t의 값은 모든 로케일에서 동일한 값을 가진 유니 코드 코드 포인트를 직접 나타냅니다. 따라서 앞에서 언급 한 로케일 간 변환을 안전하게 수행 할 수 있습니다. 그러나 대부분의 유닉스 플랫폼에서 정의하지만 Windows가 모든 로케일에서 동일한 wchar_t 로케일을 사용하더라도 Windows는 wchar_t를 이런 방식으로 사용할 수 있는지 결정하는 데에만 의존 할 수 없습니다.

Windows가 정의하지 않는 이유는 Windows가 __STDC_ISO_10646__wchar_t 인코딩으로 UTF-16을 사용하고 UTF-16이 서로 게이트 쌍을 사용하여 U + FFFF보다 큰 코드 포인트를 나타 내기 때문입니다. 즉, UTF-16이 다음의 요구 사항을 충족하지 않습니다.__STDC_ISO_10646__ .

플랫폼 특정 코드의 경우 wchar_t가 더 유용 할 수 있습니다. Windows에서 필수적으로 필요합니다 (예 : 일부 파일은 wchar_t 파일 이름을 사용하지 않고는 열 수 없음).하지만 Windows는 내가 아는 한 이것이 사실 인 유일한 플랫폼입니다 (따라서 wchar_t를 'Windows_char_t'로 생각할 수 있습니다).

돌이켜 보면 wchar_t는 텍스트 처리를 단순화하거나 로케일 독립 텍스트를위한 저장소로 유용하지 않습니다. 이식 가능한 코드를 이러한 목적으로 사용해서는 안됩니다. 이식 불가능한 코드는 일부 API에서 필요하기 때문에 유용 할 수 있습니다.

대안

내가 좋아하는 대안은 UTF-8에 특별히 친숙하지 않은 플랫폼에서도 UTF-8로 인코딩 된 C 문자열을 사용하는 것입니다.

이런 식으로 플랫폼 전반에 걸쳐 공통 텍스트 표현을 사용하여 이식 가능한 코드를 작성하고, 의도 된 목적을 위해 표준 데이터 유형을 사용하고, 해당 유형에 대한 언어 지원을 얻을 수 있습니다 (예 : 일부 컴파일러에서 작동하려면 일부 트릭이 필요하지만 문자열 리터럴). 표준 라이브러리 지원, 디버거 지원 (더 많은 트릭이 필요할 수 있음) 등. 넓은 문자를 사용하면 일반적으로이 모든 것을 얻는 것이 더 어렵거나 불가능하며 다른 플랫폼에서 다른 조각을 얻을 수 있습니다.

UTF-8이 제공하지 않는 한 가지는 ASCII에서 가능한 것과 같은 간단한 텍스트 알고리즘을 사용할 수 있다는 것입니다. 이 UTF-8에서는 다른 유니 코드 인코딩보다 나쁘지 않습니다. 사실 UTF-8의 다중 코드 단위 표현이 더 흔하고 문자의 가변 너비 표현을 처리하는 코드의 버그가 UTF를 고수하려고 할 때보 다 발견되고 수정 될 가능성이 더 높기 때문에 더 나은 것으로 간주 될 수 있습니다. -32는 NFC 또는 NFKC입니다.

많은 플랫폼에서 기본 문자 인코딩으로 UTF-8을 사용하고 많은 프로그램에서 중요한 텍스트 처리가 필요하지 않으므로 해당 플랫폼에서 국제화 된 프로그램을 작성하는 것은 국제화를 고려하지 않고 코드를 작성하는 것과 거의 다릅니다. 보다 광범위하게 이식 가능한 코드를 작성하거나 다른 플랫폼에서 작성하려면 다른 인코딩을 사용하는 API 경계에 변환을 삽입해야합니다.

일부 소프트웨어에서 사용하는 또 다른 대안은 UTF-16 데이터를 보유하는 서명되지 않은 짧은 배열과 같은 크로스 플랫폼 표현을 선택한 다음 모든 라이브러리 지원을 제공하고 단순히 언어 지원 비용을 감수하는 것입니다.

C ++ 11은 보조 언어 / 라이브러리 기능을 사용하여 wchar_t, char16_t 및 char32_t에 대한 대안으로 새로운 종류의 와이드 문자를 추가합니다. 실제로 UTF-16 및 UTF-32가 보장되지는 않지만 주요 구현이 다른 것을 사용할 것이라고는 생각하지 않습니다. C ++ 11은 또한 UTF-8 지원을 향상시킵니다. 예를 들어 UTF-8 문자열 리터럴을 사용하면 VC ++를 속여서 UTF-8 인코딩 문자열을 생성 할 필요가 없습니다 (비록 계속 사용할 수도 있지만u8 접두사를 ). .

피해야 할 대안

TCHAR : TCHAR는 레거시 인코딩을 가정하는 고대 Windows 프로그램을 char에서 wchar_t로 마이그레이션하는 데 사용되며 프로그램이 이전 천년에 작성된 경우가 아니면 잊어 버리는 것이 가장 좋습니다. 이식성이 없으며 인코딩 및 데이터 유형에 대해 본질적으로 불특정하여 TCHAR 기반이 아닌 API에서 사용할 수 없습니다. 목적이 wchar_t 로의 마이그레이션이기 때문에 위에서 본 것은 좋은 생각이 아니므로 TCHAR를 사용하는 데 아무런 가치가 없습니다.


1. wchar_t 문자열로 표현할 수 있지만 어떤 로케일에서도 지원되지 않는 문자는 단일 wchar_t 값으로 표현할 필요가 없습니다. 이것은 wchar_t가 특정 문자에 대해 가변 너비 인코딩을 사용할 수 있음을 의미하며, wchar_t의 의도에 대한 또 다른 명백한 위반입니다. wchar_t로 표현할 수있는 문자는 로케일이 해당 문자를 '지원'한다고 말하기에 충분하지만,이 경우 가변 너비 인코딩은 합법적이지 않으며 Window의 UTF-16 사용은 부적합합니다.

2. 유니 코드를 사용하면 여러 문자를 여러 코드 포인트로 표현할 수 있으므로 간단한 텍스트 알고리즘에 대해 가변 너비 인코딩과 동일한 문제가 발생합니다. 구성된 정규화를 엄격하게 유지하더라도 일부 문자에는 여전히 여러 코드 포인트가 필요합니다. 참조 : http://www.unicode.org/standard/where/


3
추가 : utf8everywhere.org 는 Windows에서 UTF-8 사용을 권장하며 Boost.Nowide는 공식 검토를 위해 예정되어 있습니다.
Yakov Galka 2012-06-22

2
물론 가장 좋은 방법은 Windows에서 C # 또는 VB.Net을 사용하는 것입니다. :) 또는 평범한 C / Win32입니다. 그러나 C ++를 사용해야한다면 TCHAR이 가장 좋은 방법입니다. MSVS2005 이상에서 기본값은 "wchar_t"입니다. IMHO ...
paulsm4

4
@BrendanMcK : 물론, Windows에서 Win32 API를 사용하고 다른 시스템에서 다른 API를 사용하는 코드는 존재하지 않습니다. 권리? Microsoft의 접근 방식 ( "앱의 모든 곳에서 내부적으로 wchar 사용")의 문제점은 시스템에 직접 인터페이스하지 않고 이식 할 수 있는 코드에도 영향을 미친다는 것입니다 .
Yakov Galka 2012-06-24

4
문제는 당신이 있다는 것입니다 은 ANSI 코드 페이지로 마이크로 소프트의 결정으로 인해되지 지원 UTF-8로 "휴식"표준 C (++) 라이브러리 Windows 특정 기능을 사용 할 수 있습니다. 예를 들어 fopen이름에 ANSI가 아닌 문자가 포함 된 파일은 사용할 수 없습니다 .
dan04

11
@ dan04 예, Windows에서는 표준 라이브러리를 사용할 수 없지만 다른 플랫폼에서 표준 라이브러리를 래핑하고 Win32 W 함수를 사용하기 직전에 UTF-8에서 wchar_t로 변환하는 이식 가능한 인터페이스를 만들 수 있습니다.
bames53

20

wchar_t에는 "잘못된"것이 없습니다. 문제는 NT 3.x 시절에 마이크로 소프트가 유니 코드가 좋다고 결정하고 유니 코드를 16 비트, wchar_t 문자로 구현했다는 것입니다. 따라서 90 년대 중반의 대부분의 Microsoft 문헌은 유니 코드 == utf16 == wchar_t와 거의 동일합니다.

슬프게도 전혀 그렇지 않습니다. "와이드 문자"는 모든 상황에서 모든 플랫폼에서 반드시 2 바이트 가 아닙니다 .

이것은 "유니 코드"에 대한 최고의 입문서 중 하나입니다 (이 질문과 무관하고 C ++와 무관). 저는 이것을 강력히 추천합니다.

그리고 솔직히 "8 비트 ASCII"대 "Win32 와이드 문자"대 "wchar_t-in-general"을 처리하는 가장 좋은 방법은 단순히 "Windows는 다르다"라는 것을 받아들이고 그에 따라 코드를 작성하는 것입니다.

IMHO ...

추신:

위의 jamesdlin에 전적으로 동의합니다.

Windows에서는 선택의 여지가 없습니다. 내부 API는 UCS-2 용으로 설계되었는데, 이는 가변 길이 UTF-8 및 UTF-16 인코딩이 표준화되기 전 이었기 때문에 당시에는 합리적이었습니다. 그러나 이제 UTF-16을 지원하므로 두 세계 모두에서 최악의 상황이되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.