나는의 사용을 원망는 C ++ 커뮤니티 (는 Freenode에 특히 ## C ++)에서 많은 사람들을 보았다 wstrings
하고 wchar_t
, 그리고 윈도우 API에서의 사용. wchar_t
및 wstring
에서 정확히 "잘못된"것은 무엇이며 국제화를 지원하려는 경우 와이드 문자에 대한 몇 가지 대안은 무엇입니까?
나는의 사용을 원망는 C ++ 커뮤니티 (는 Freenode에 특히 ## C ++)에서 많은 사람들을 보았다 wstrings
하고 wchar_t
, 그리고 윈도우 API에서의 사용. wchar_t
및 wstring
에서 정확히 "잘못된"것은 무엇이며 국제화를 지원하려는 경우 와이드 문자에 대한 몇 가지 대안은 무엇입니까?
답변:
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를 로케일 간의 텍스트에 대한 공통 표현으로 사용하거나 간단한 텍스트 알고리즘을 사용할 수 없음을 의미합니다.
어쨌든 이식 가능한 코드는 많지 않습니다. __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/
fopen
이름에 ANSI가 아닌 문자가 포함 된 파일은 사용할 수 없습니다 .
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을 지원하므로 두 세계 모두에서 최악의 상황이되었습니다.