std :: wstring VS 표준 :: string


741

나는 사이의 차이점을 이해 할 수없는 생각 std::stringstd::wstring. wstring유니 코드 문자와 같은 넓은 문자를 지원한다는 것을 알고 있습니다. 다음과 같은 질문이 있습니다.

  1. 언제 std::wstring이상 사용해야 std::string합니까?
  2. std::string특수 문자를 포함하여 전체 ASCII 문자 세트를 보유 할 수 있습니까 ?
  3. 되어 std::wstring모든 인기있는 C ++ 컴파일러에 의해 지원?
  4. 정확히 " 와이드 캐릭터 " 란 무엇입니까 ?

10
ASCII 문자 집합에는 "특수"문자가 많지 않으며 가장 이국적인 문자는 아마도`(역 따옴표) 일 것입니다. std :: string은 모든 유니 코드 문자의 약 0.025 % (보통 8 비트 문자)를 보유 할 수 있습니다
MSalters

3
넓은 문자 및 사용할 유형에 대한 좋은 정보는 여기에서 찾을 수 있습니다. programmers.stackexchange.com/questions/102205/…
Yariv

14
글쎄, 그리고 우리가 2012 년부터 utf8everywhere.org 가 작성되었습니다. C ++ / Windows의 권리와 잘못에 관한 모든 질문에 거의 대답합니다.
Pavel Radzivilovsky 2018 년

42
@MSalters : std :: string은 CHAR_BIT가 8 인 경우에도 모든 유니 코드 문자의 100 %를 보유 할 수 있습니다. 이는 시스템 수준에서 UTF-8 일 수있는 std :: string의 인코딩에 따라 다릅니다 (Windows를 제외한 거의 모든 곳 에서처럼) ) 또는 응용 프로그램 수준에서. 기본 좁은 인코딩은 유니 코드를 지원하지 않습니까? 문제 없습니다. 그냥 사용하지 말고 UTF-8을 대신 사용하십시오.
Yakov Galka 2016 년

8
이 주제에 대한 다양한 독서 utf8everywhere.org
디모데 방패

답변:


991

string? wstring?

std::stringA는 basic_stringA의 템플릿 char, 및 std::wstringA의 wchar_t.

char vs. wchar_t

char문자, 보통 8 비트 문자를 포함해야합니다.
wchar_t넓은 문자를 개최하기로하고, 일이 힘들 수있다 :
리눅스에,이 wchar_t윈도우에, 그것은 2 바이트있는 동안, 4 바이트입니다.

그렇다면 유니 코드 는 어떻습니까?

문제는 유니 코드에 직접적으로 charwchar_t직접 연결되어 있지도 않습니다 .

리눅스에서?

리눅스 OS를 보자 : 우분투 시스템은 이미 유니 코드를 인식하고있다. char 문자열로 작업 할 때 기본적으로 UTF-8로 인코딩됩니다 (즉, 유니 코드 문자열). 다음 코드 :

#include <cstring>
#include <iostream>

int main(int argc, char* argv[])
{
   const char text[] = "olé" ;


   std::cout << "sizeof(char)    : " << sizeof(char) << std::endl ;
   std::cout << "text            : " << text << std::endl ;
   std::cout << "sizeof(text)    : " << sizeof(text) << std::endl ;
   std::cout << "strlen(text)    : " << strlen(text) << std::endl ;

   std::cout << "text(ordinals)  :" ;

   for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
   {
      std::cout << " " << static_cast<unsigned int>(
                              static_cast<unsigned char>(text[i])
                          );
   }

   std::cout << std::endl << std::endl ;

   // - - - 

   const wchar_t wtext[] = L"olé" ;

   std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl ;
   //std::cout << "wtext           : " << wtext << std::endl ; <- error
   std::cout << "wtext           : UNABLE TO CONVERT NATIVELY." << std::endl ;
   std::wcout << L"wtext           : " << wtext << std::endl;

   std::cout << "sizeof(wtext)   : " << sizeof(wtext) << std::endl ;
   std::cout << "wcslen(wtext)   : " << wcslen(wtext) << std::endl ;

   std::cout << "wtext(ordinals) :" ;

   for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
   {
      std::cout << " " << static_cast<unsigned int>(
                              static_cast<unsigned short>(wtext[i])
                              );
   }

   std::cout << std::endl << std::endl ;

   return 0;
}

다음 텍스트를 출력합니다.

sizeof(char)    : 1
text            : olé
sizeof(text)    : 5
strlen(text)    : 4
text(ordinals)  : 111 108 195 169

sizeof(wchar_t) : 4
wtext           : UNABLE TO CONVERT NATIVELY.
wtext           : ol�
sizeof(wtext)   : 16
wcslen(wtext)   : 3
wtext(ordinals) : 111 108 233

"olé"텍스트 char는 실제로 110, 108, 195 및 169 (후행 0을 세지 않음)의 네 문자로 구성됩니다. ( wchar_t코드를 연습으로 공부하도록하겠습니다 )

따라서 charLinux에서 작업 할 때는 일반적으로 몰라도 유니 코드를 사용해야합니다. 와 함께 std::string작동 char하므로 std::string이미 유니 코드 준비가되어 있습니다.

참고 std::string는 C 문자열 API처럼 "올레"문자열을 고려할 것은 4 자,없는 세 가지가 있습니다. 따라서 UTF-8에서는 일부 문자 조합이 금지되므로 유니 코드 문자로 자르거나 재생할 때주의해야합니다.

Windows에서?

Windows에서는 약간 다릅니다. Win32에서 함께 응용 프로그램 작업을 많이 지원했다 char다른에 캐릭터 세트 / 코드 페이지 유니 코드의 출현하기 전에, 전 세계에서 생산.

따라서 해결책은 흥미로 웠습니다. 응용 프로그램이에서 작동하는 char경우 문자 스트링은 기계의 로컬 문자 세트 / 코드 페이지를 사용하여 GUI 레이블에 인코딩 / 인쇄 / 표시됩니다. 예를 들어 프랑스어로 지역화 된 Windows에서는 "olé"가 "olé"이지만 키릴 지역화 된 Windows ( Windows-1251 을 사용하는 경우 "olй")에서는 다릅니다 . 따라서 "역사 앱"은 일반적으로 이전과 동일하게 작동합니다.

유니 코드 기반 응용 프로그램의 경우 Windows wchar_t는 2 바이트 너비의을 사용하고 UTF-16으로 인코딩됩니다. UTF-16 은 2 바이트 문자로 인코딩 된 유니 코드 (또는 대부분 가장 호환되는 UCS-2) 같은 것 IIRC).

사용 char하는 응용 프로그램 은 "각 바이트가 하나 이상의 chars 로 구성되어 있기 때문에" "멀티 바이트"라고 하며, 사용하는 응용 프로그램 wchar_t은 "각 문자가 하나 또는 두 개로 구성되므로"widechar "라고 wchar_t합니다. 자세한 내용은 MultiByteToWideCharWideCharToMultiByte Win32 변환 API를 참조하십시오.

따라서 Windows에서 작업하는 경우 GTK + 또는 QT 와 같이 숨어있는 프레임 워크를 사용하지 않는 한 사용 하기원치wchar_t 않습니다 . 사실, 뒤에서 Windows는 문자열로 작동 하므로 역사적인 응용 프로그램조차도 API 를 사용할 때 문자열이 변환됩니다 (Win32 GUI에서 레이블을 설정하는 저수준 API 기능).wchar_tcharwchar_tSetWindowText()

메모리 문제?

UTF-32는 문자 당 4 바이트이므로 UTF-8 텍스트와 UTF-16 텍스트 만 항상 UTF-32 텍스트보다 적거나 같은 양의 메모리를 사용하는 경우 추가 할 것이 많지 않습니다. ).

메모리 문제가있는 경우 대부분의 서구 언어보다 UTF-8 텍스트가 동일한 UTF-16 텍스트보다 적은 메모리를 사용합니다.

여전히 다른 언어 (중국어, 일본어 등)의 경우 사용되는 메모리는 UTF-16의 경우와 동일하거나 UTF-16의 경우 약간 더 큽니다.

대체로 UTF-16은 문자 당 2 바이트와 4 바이트를 주로 사용합니다 (특별한 언어 글리프 (Klingon? Elvish?)를 처리하지 않는 한 UTF-8은 1 ~ 4 바이트를 소비합니다.

자세한 내용은 http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 을 참조하십시오 .

결론

  1. std :: string보다 std :: wstring을 사용해야 할 때?

    리눅스에서? 거의 없다 (§).
    Windows에서? 거의 언제나 (§).
    크로스 플랫폼 코드? 툴킷에 따라 ...

    (§) : 툴킷 / 프레임 워크를 사용하지 않는 한

  2. std::string특수 문자를 포함한 모든 ASCII 문자 세트를 보유 할 수 있습니까 ?

    주의 : A std::string는 '이진'버퍼를 유지하는 데 적합합니다 std::wstring.

    리눅스에서? 예.
    Windows에서? Windows 사용자의 현재 로캘에는 특수 문자 만 사용할 수 있습니다.

    편집 ( Johann Gerell 의 주석 후 ) :
    a std::string는 모든 char기반 문자열 을 처리하기에 충분합니다 (각각 char0에서 255까지의 숫자 임). 그러나:

    1. ASCII는 0에서 127 사이 여야합니다. 더 높은 chars는 ASCII가 아닙니다.
    2. char0에서 127까지 제대로 개최됩니다
    3. char128 ~ 255은 부호화 (유니, 유니 코드 등)에 따라 의미가되지만, 그들은 UTF-8 인코딩으로는 종일 유니 코드 글리프를 보유 할 수있을 것이다.
  3. 되어 std::wstring거의 모든 인기있는 C ++ 컴파일러에 의해 지원?

    주로 Windows로 포팅되는 GCC 기반 컴파일러는 예외입니다.
    g ++ 4.3.2 (Linux)에서 작동하며 Visual C ++ 6 이후 Win32에서 유니 코드 API를 사용했습니다.

  4. 정확히 넓은 캐릭터는 무엇입니까?

    C / C ++에서는 wchar_t단순 char문자 유형 보다 큰 문자 유형으로 작성되었습니다 . 유니 코드 글리프와 같은 인덱스가 255보다 큰 문자 (또는 127, ...에 따라 다름)에 넣는 데 사용됩니다.


4
@gnud : 아마도 wchar_t는 UTF-16이 출현하기 전에 모든 UCS-2 문자 (대부분의 UTF-16 문자)를 처리하기에 충분했을 것입니다. Win32에서 char의 코드 페이지 사용을 수정하지 않고.
paercebal

4
@Sorin Sbarnea : UTF-8은 1-6 바이트를 취할 수 있지만 분명히 표준은 1-4 바이트로 제한합니다. 자세한 내용은 en.wikipedia.org/wiki/UTF8#Description 을 참조하십시오.
paercebal

8
이 예제는 Linux 및 Windows에서 다른 결과를 생성하지만 C ++ 프로그램에는 olèUTF-8로 인코딩 되는지 여부에 대한 구현 정의 동작이 포함되어 있습니다 . 더 나아가, 당신은 할 수없는 이유는 기본적으로 스트림 wchar_t *에이 std::cout유형이 잘못 형성 프로그램의 결과로 호환되지 않는 그것은 인코딩의 사용과 아무 상관이 없기 때문이다. 특히 코드를 이식 가능하게하려는 경우 플랫폼이 아닌 자체 인코딩 기본 설정 을 사용하는지 std::string또는 std::wstring의존 하는지 여부를 지적하는 것이 좋습니다.
John Leidegren

14
Windows는 실제로 UTF-16을 사용하며 꽤 오랫동안 사용되었습니다. 구 버전의 Windows는 UCS-2를 사용했지만 더 이상 그렇지 않습니다. 내 유일한 문제는 std::wstring내가 잘못 생각하는 유니 코드 Windows API에 더 적합하기 때문에 Windows에서 사용해야한다는 결론입니다 . 유일한 관심사는 유니 코드 Windows API를 호출하고 문자열을 마샬링하지 않는 경우 확실하지만 일반적인 경우로는 이것을 구입하지 않습니다.
John Leidegren

15
@ John Leidegren : If your only concern was calling into the Unicode Windows API and not marshalling strings then sure: 그럼 동의합니다. JavaScript가 아닌 C ++로 코딩하고 있습니다. 컴파일 타임에 수행 할 수있는 런타임에서 쓸모없는 마샬링 또는 기타 잠재적으로 많은 비용이 드는 처리를 피하는 것이 언어의 핵심입니다. WinAPI를 코딩하고 사용 std::string하는 것은 정당하지 않은 런타임 자원 일뿐입니다. 당신은 그것이 잘못되어 있고 당신의 관점이므로 괜찮습니다. 내 자신은 Linux 측에서 더 잘 보이기 때문에 Windows에서 비관 화로 코드를 작성하지 않는다는 것입니다.
paercebal

71

std::wstring인터페이스에서 요구되는 경우를 제외하고 Windows API 호출 및 구문 변환으로 각 인코딩 변환 근처의 경우를 제외하고 Windows 또는 다른 곳 에서는 피하는 것이 좋습니다 .

내 의견은 http://utf8everywhere.org 에 요약되어 있으며 공동 저자입니다.

응용 프로그램이 주로 API 응용 프로그램과 같은 API 호출 중심이 아닌 경우 유니 코드 문자열을 std :: string에 저장하고 UTF-8로 인코딩하여 API 호출 근처에서 변환을 수행하는 것이 좋습니다. 이 기사에 요약 된 이점은 특히 복잡한 응용 프로그램에서 명백한 변환 성가심보다 중요합니다. 이것은 다중 플랫폼 및 라이브러리 개발에있어 이중입니다.

그리고 지금, 당신의 질문에 대답하십시오 :

  1. 몇 가지 약한 이유. widechars가 유니 코드를 지원하는 적절한 방법으로 여겨지는 역사적인 이유로 존재합니다. UTF-16 문자열을 선호하는 API를 인터페이스하는 데 사용됩니다. 나는 그러한 API 호출의 직접적인 근처에서만 사용합니다.
  2. 이것은 std :: string과 관련이 없습니다. 어떤 인코딩이든 넣을 수 있습니다. 유일한 문제는 어떻게 당신은 그 내용을 취급합니다. 내 권장 사항은 UTF-8이므로 모든 유니 코드 문자를 올바르게 보유 할 수 있습니다. Linux에서는 일반적인 관행이지만 Windows 프로그램에서도 그렇게해야한다고 생각합니다.
  3. 아니.
  4. 넓은 문자는 혼란스러운 이름입니다. 유니 코드 초기에는 문자를 2 바이트로 인코딩 할 수 있다는 믿음이 있었으므로 이름입니다. 현재는 "2 바이트 길이의 문자"를 의미합니다. UTF-16은 이러한 바이트 쌍의 시퀀스 (일명 와이드 문자)로 표시됩니다. UTF-16의 문자는 하나 또는 두 쌍을 취합니다.

37

따라서 여기에있는 모든 독자는 사실과 상황에 대해 분명하게 이해해야합니다. 그렇지 않다면, 당신은 paercebal의 탁월하게 포괄적 인 답변 [btw : thanks!]을 읽어야합니다 .

필자의 실제적인 결론은 놀랍게도 간단하다. C ++ (및 STL) "문자 인코딩"은 모두 실질적으로 깨져서 쓸모가 없다. 어쨌든 도움이되지 않을 것이라고 Microsoft에서 비난하십시오.

내 솔루션, 심층 조사 후 많은 좌절과 결과적 경험은 다음과 같습니다.

  1. 인코딩 및 변환에 대한 책임은 사용자 본인에게 있습니다 (그리고 그 중 상당 부분이 사소한 것임을 알 수 있습니다)

  2. 사용 표준 : 어떤 UTF-8로 인코딩 된 문자열을 문자열 (단지를 typedef std::string UTF8String)

  3. 그러한 UTF8String 객체는 멍청하지만 저렴한 컨테이너라는 것을 받아들입니다. 절대로 직접 문자에 액세스하거나 조작하지 마십시오 (검색, 교체 등). 당신은 할 수 있지만, 정말로, 정말, 멀티 바이트 문자열에 대한 텍스트 조작 알고리즘을 작성하는 데 시간을 낭비하고 싶지 않습니다! 다른 사람들이 이미 그런 멍청한 짓을 했더라도 그렇게하지 마십시오! 순리에 맡기다! (잘 이해되는 시나리오가 있습니다. ICU 라이브러리 만 사용하십시오).

  4. UCS-2로 인코딩 된 문자열에 std :: wstring을 사용하십시오 ( typedef std::wstring UCS2String)-이것은 WIN32 API가 도입 한 혼란에 대한 타협이며 양보입니다). UCS-2는 우리 대부분에게 충분합니다 (나중에 자세히 설명합니다).

  5. 문자 별 액세스가 필요할 때마다 (읽기, 조작 등) UCS2String 인스턴스를 사용하십시오. 모든 문자 기반 처리는 비 멀티 바이트 표현으로 수행해야합니다. 간단하고 빠르며 쉽습니다.

  6. UTF-8과 UCS-2 사이에서 앞뒤로 변환하는 두 가지 유틸리티 함수를 추가하십시오.

    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );

변환은 간단합니다 .Google은 여기에 도움이되어야합니다 ...

그게 다야. 메모리가 중요한 모든 UTF-8 I / O에 UTF8String을 사용하십시오. 문자열을 구문 분석 및 / 또는 조작해야 할 때마다 UCS2String을 사용하십시오. 이 두 표현 사이를 언제든지 변환 할 수 있습니다.

대안 및 개선

  • & 1 바이트 문자 인코딩 (예 : ISO-8859-1)에서 &으로의 변환은 일반 변환 표, 예를 들어 const wchar_t tt_iso88951[256] = {0,1,2,...};UCS2 와의 변환을위한 적절한 코드의 도움으로 실현 될 수 있습니다 .

  • UCS-2가 충분하지 않은 경우 UCS-4 ( typedef std::basic_string<uint32_t> UCS2String)로 전환

ICU 또는 다른 유니 코드 라이브러리?

고급 재료.


Dang, 네이티브 유니 코드 지원이 없다는 것을 아는 것은 좋지 않습니다.
Mihai Danila

@ Frunsi, Glib :: ustring을 사용해 보았는지 궁금하다면 어떻게 생각하십니까?
Caroline Beltran

@CarolineBeltran : 나는 Glib을 알고 있지만 결코 사용하지 않았으며 아마도 특정하지 않은 대상 플랫폼 (유닉스 시스템 ...)으로 제한되어 있기 때문에 결코 사용하지 않을 것입니다. Windows 포트는 외부 win2unix 계층을 기반으로하며 IMHO는 OSX 호환 계층이 전혀 없습니다. 이 모든 것은 적어도 내 코드 (이 아치 수준에서 ...) ;-)에 대해 잘못된 방향으로 명확하게 지시됩니다. 따라서 Glib는 옵션이 아닙니다.
Frunsi

9
검색, 바꾸기 등은 UTF-8 문자열에서 잘 작동합니다 (문자를 나타내는 바이트 시퀀스의 일부는 다른 문자로 잘못 해석 될 수 없습니다). 실제로 UTF-16과 UTF-32는 이것을 전혀 쉽게 만들지 않습니다. 사용자 인식 문자 (그래프 클러스터)는 여러 유니 코드 코드 포인트가 될 수 있기 때문에 실제로 3 개의 인코딩은 모두 멀티 바이트 인코딩입니다! 실용적인 솔루션은 모든 것에 UTF-8을 사용하고 Windows API를 다룰 때만 UTF-16으로 변환하는 것입니다.
Daniel

5
@Frunsi : 검색 및 바꾸기는 UTF-32와 마찬가지로 UTF-8에서도 잘 작동합니다. UTF-8과 같은 가변 길이 인코딩을 사용하면 문자열 처리가 더 이상 복잡해지지 않기 때문에 올바른 유니 코드 인식 텍스트 처리가 다중 코드 포인트 '문자'를 처리해야하기 때문입니다. 따라서 어디서나 UTF-8을 사용하십시오. 일반적인 C 문자열 함수는 UTF-8에서 잘 작동하고 (유니 코드 문자열의 서수 비교에 해당) 언어 인식이 더 필요한 경우 어쨌든 UTF-16 / 32의 유니 코드 라이브러리를 호출해야합니다 그것에서 당신을 저장할 수 없습니다.
Daniel

25
  1. 넓은 문자를 문자열에 저장하려는 경우. wide구현에 따라 다릅니다. 올바르게 기억하면 Visual C ++의 기본값은 16 비트이며 GCC는 대상에 따라 기본값입니다. 여기는 32 비트입니다. wchar_t (와이드 문자 유형)는 유니 코드와 관련이 없습니다. 구현이 로케일이 지원하는 가장 큰 문자 세트의 모든 멤버를 최소한 char만큼 저장할 수 있다는 것만 보장됩니다. 인코딩 을 사용하여 유니 코드 문자열을 잘 저장할 수 있습니다 . 그러나 유니 코드 코드 포인트의 의미를 이해하지 못합니다. 그래서std::stringutf-8str.size()문자열에 논리적 문자의 양을 제공하지는 않지만 해당 문자열 / wstring에 저장된 char 또는 wchar_t 요소의 양만 제공합니다. 이런 이유로 gtk / glib C ++ 래퍼 사람들은 Glib::ustringutf-8을 처리 할 수 있는 클래스를 개발했다 .

    경우 당신은 wchar_t가 긴 32 비트입니다, 당신은 사용할 수 utf-32유니 코드 인코딩으로, 당신은 저장할 수 고정 (UTF-32은 고정 길이) 인코딩을 사용하여 핸들 유니 코드 문자열. 이것은 wstring의 s.size()함수가 올바른 양의 wchar_t 요소 논리 문자 반환 한다는 것을 의미합니다 .

  2. 예, char의 길이는 항상 8 비트 이상이므로 모든 ASCII 값을 저장할 수 있습니다.
  3. 예, 모든 주요 컴파일러에서 지원합니다.

# 2가 궁금합니다. 7 비트가 기술적으로 유효하다고 생각 했습니까? 또는 7 비트 ASCII 문자를 지난 항목을 저장할 수 있어야합니까?
jalf December

1
예, jalf. c89는 limits.h (서명되지 않은 char의 경우 0..255 분) 및 정수 유형의 순수 이진 시스템 문서에서 기본 유형의 최소 범위를 지정합니다. char, unsigned char 및 signed char의 최소 비트 길이는 8입니다. c ++는 이러한 규칙을 상속합니다.
Johannes Schaub-litb

15
"이는 wstring의 s.size () 함수가 올바른 양의 wchar_t 요소와 논리 문자를 반환한다는 것을 의미합니다." 이것은 유니 코드의 경우에도 완전히 정확하지는 않습니다. UTF-32에서도 주어진 문자가 여러 개의 코드 포인트로 구성 될 수 있지만 "논리적 문자"보다 코드 포인트를 말하는 것이 더 정확합니다.
로건 카파도

본질적으로 C ++은 유니 코드 문자 집합을 기본적으로 지원하지 않는다고 말하는가?
Mihai Danila

1
"하지만 유니 코드 코드 포인트의 의미를 이해하지 못합니다." Windows에서는 어느 쪽도 아닙니다 std::wstring.
중복 제거기

5

나는 종종 std :: string을 사용하여 아무런 문제없이 utf-8 문자를 보유합니다. utf-8을 기본 문자열 유형으로 사용하는 API와 인터페이스 할 때이 작업을 수행하는 것이 좋습니다.

예를 들어, 코드를 Tcl 인터프리터와 인터페이스 할 때 utf-8을 사용합니다.

주요 경고는 std :: string의 길이이며 더 이상 문자열의 문자 수가 아닙니다.


1
Juan : std :: string이 모든 유니 코드 문자를 포함 할 수 있지만 길이가 잘못보고된다는 것을 의미합니까? 잘못된 길이를보고하는 이유가 있습니까?

3
utf-8 인코딩을 사용할 때 단일 유니 코드 문자는 여러 바이트로 구성 될 수 있습니다. 이것이 표준 ASCII 세트의 문자를 주로 사용할 때 utf-8 인코딩이 더 작은 이유입니다. 유니 코드 문자 수를 측정하려면 특수 기능을 사용하거나 자신의 롤을 사용해야합니다.

2
(Windows에만 해당) 대부분의 함수는 바이트를 사용하는 문자열이 ASCII이고 2 바이트는 유니 코드 (이전 버전 MBCS) 인 것으로 예상합니다. 즉, 8 비트 유니 코드를 저장하는 경우 16 비트 유니 코드로 변환하여 표준 Windows 함수를 호출해야합니다 (ASCII 부분 만 사용하지 않는 한).
Greg Domjan

2
std :: string은 길이를 잘못보고 할뿐만 아니라 잘못된 문자열도 출력합니다. 일부 유니 코드 문자가 UTF-8에서 다중 바이트로 표시되어 std :: string이 자체 문자로 생각하면 일반적으로 std :: string 조작 루틴은 아마도 하나의 잘못된 해석으로 인해 몇 가지 이상한 문자를 출력합니다. 올바른 캐릭터.
Mihai Danila

2
문자열을 바이트 컨테이너로만 생각하도록 표시를 변경하고 바이트가 유니 코드 인코딩 (UTF-8, UTF-16, ...) 인 경우 이해하는 특정 라이브러리를 사용해야합니다 그. 표준 문자열 기반 API (길이, substr 등)는 모두 멀티 바이트 문자로 비참하게 실패합니다. 이 업데이트가 이루어지면 다운 보트를 제거합니다.
Mihai Danila

4
  1. 'wide'(유니 코드) 문자를 저장하려는 경우
  2. 예 : 255 개 (0 제외)
  3. 예.
  4. 소개 기사는 다음과 같습니다. http://www.joelonsoftware.com/articles/Unicode.html

11
std :: string은 0을 잘 유지할 수 있습니다 (c_str () 메서드를 호출하면 조심하십시오)
Mr Fooz

3
엄밀히 말하면, 문자는 8 비트가 보장되지 않습니다. :) # 4의 링크는 반드시 읽어야하지만 질문에 대한 답변은 아닙니다. 넓은 문자는 유니 코드와 전혀 관련이 없습니다. 단순히 더 넓은 성격입니다. (OS에 따라 더 넓지 만 일반적으로 16 또는 32 비트)
jalf

2
  1. ASCII가 아닌 유니 코드 문자열을 사용하려는 경우 국제화에 도움이됩니다.
  2. 예,하지만 0에서는 잘 재생되지 않습니다
  3. 모르는 것을 알지 못한다
  4. 와이드 문자는 유니 코드 문자의 고정 길이 표현을 처리하는 컴파일러 특정 방식입니다 .MSVC의 경우 2 바이트 문자입니다 .gcc의 경우 4 바이트임을 이해합니다. http://www.joelonsoftware.com/articles/Unicode.html의 경우 +1

1
2. std :: string은 NULL 문자를 그대로 유지할 수 있습니다. 또한 utf-8 및 와이드 문자도 보유 할 수 있습니다.

@Juan : 다시 혼란에 빠졌습니다. std :: string이 유니 코드 문자를 유지할 수 있다면 std :: wstring의 특별한 점은 무엇입니까?

1
@Appu : std :: string은 UTF-8 유니 코드 문자를 보유 할 수 있습니다. 다양한 문자 너비를 대상으로하는 여러 가지 유니 코드 표준이 있습니다. UTf8은 8 비트 폭입니다. 16 비트와 32 비트 너비의 UTF-16과 UTF-32도 있습니다
Greg D

std :: wstring을 사용하십시오. 고정 길이 인코딩을 사용할 때 각 유니 코드 문자는 하나의 wchar_t 일 수 있습니다. 예를 들어 Greg가 링크 할 때 소프트웨어에서 joel 접근 방식을 사용하도록 선택한 경우. 그런 다음 wstring의 길이는 문자열에서 정확히 유니 코드 문자 수입니다. 그러나 더 많은 공간을 차지

나는 0 '\ 0'을 가질 수 없다고 말하지 않았고, 내가 의미하는 바는 제대로 작동하지 않는다는 것입니다. 일부 메소드는 wstring의 모든 데이터를 포함하는 예상 결과를 제공하지 않을 수 있습니다. 다운 투표에 너무 가혹합니다.
Greg Domjan

2

256 개의 다른 문자만으로 만족되지 않는 응용 프로그램은 와이드 문자 (8 비트 이상) 또는 UTF-8과 같은 가변 길이 인코딩 (C ++ 용어의 멀티 바이트 인코딩)을 사용할 수 있습니다. 와이드 문자는 일반적으로 가변 길이 인코딩보다 더 많은 공간이 필요하지만 처리 속도가 더 빠릅니다. 많은 양의 텍스트를 처리하는 다국어 응용 프로그램은 일반적으로 텍스트를 처리 할 때 넓은 문자를 사용하지만 디스크에 저장할 때는 UTF-8로 변환합니다.

a string와 a 의 유일한 차이점은 wstring저장된 문자의 데이터 유형입니다. 문자열은 char크기가 8 비트 이상으로 보장되는을 저장 하므로 ASCII, ISO-8859-15 또는 UTF-8 텍스트와 같은 문자열을 처리에 사용할 수 있습니다. 표준은 문자 집합이나 인코딩에 대해서는 아무 것도 말하지 않습니다.

실제로 모든 컴파일러는 처음 128자가 ASCII와 일치하는 문자 세트를 사용합니다. UTF-8 인코딩을 사용하는 컴파일러의 경우에도 마찬가지입니다. UTF-8 또는 다른 가변 길이 인코딩에서 문자열을 사용할 때 알아 두어야 할 중요한 사항은 문자와 숫자가 아닌 바이트 단위로 인덱스와 길이를 측정한다는 것입니다.

wstring의 데이터 유형은 wchar_t표준에서 정의되지 않은 크기이며, 최소한 char만큼 크거나 보통 16 비트 또는 32 비트 여야합니다. wstring을 사용하여 구현 정의 된 와이드 문자 인코딩에서 텍스트를 처리 할 수 ​​있습니다. 인코딩은 표준에 정의되어 있지 않기 때문에 문자열과 wstring 사이를 변환하는 것은 간단하지 않습니다. wstring에 고정 길이 인코딩이 있다고 가정 할 수는 없습니다.

다국어 지원이 필요하지 않은 경우 일반 문자열 만 사용하는 것이 좋습니다. 반면에 그래픽 응용 프로그램을 작성하는 경우 API가 넓은 문자 만 지원하는 경우가 종종 있습니다. 그런 다음 텍스트를 처리 할 때 동일한 와이드 문자를 사용하려고합니다. UTF-16은 가변 길이 인코딩이므로 length()문자 수를 리턴 한다고 가정 할 수 없습니다 . API가 UCS-2와 같은 고정 길이 인코딩을 사용하면 처리가 쉬워집니다. 와이드 문자와 UTF-8 사이의 변환은 이식 가능한 방식으로 수행하기가 어렵지만 사용자 인터페이스 API는 변환을 지원할 수 있습니다.


따라서 첫 번째 단락을 표현하면 256자를 초과하는 응용 프로그램은 멀티 바이트 인코딩 또는 maybe_multibyte 인코딩을 사용해야합니다.
중복 제거기

그러나 일반적으로 UCS-2 및 UCS-4와 같은 16 및 32 비트 인코딩을 멀티 바이트 인코딩이라고하지는 않습니다. C ++ 표준은 멀티 바이트 인코딩과 와이드 문자를 구분합니다. 넓은 문자 표현은 문자 당 고정 된 숫자 (일반적으로 8 개 이상) 비트를 사용합니다. 가장 일반적인 문자를 인코딩하기 위해 단일 바이트를 사용하고 나머지 문자 세트를 인코딩하기 위해 여러 바이트를 인코딩하는 것을 멀티 바이트 인코딩이라고합니다.
Seppo Enarvi

죄송합니다. 가변 길이 인코딩이 있어야합니다. UTF-16은 UTF-8과 마찬가지로 가변 길이 인코딩입니다. 척하는 것은 나쁜 생각 이 아닙니다 .
중복 제거기

그건 좋은 지적이야. wstring을 사용하여 UTF-16 (UCS-2 대신)을 저장할 수 없었던 이유는 없지만 고정 길이 인코딩의 편리함이 손실됩니다.
Seppo Enarvi

2

좋은 질문입니다! DATA ENCODING (때로는 CHARSET포함됨 )은 데이터를 파일에 저장하거나 네트워크를 통해 데이터를 전송하기 위한 메모리 표현 메커니즘 이라고 생각 하므로이 질문에 다음과 같이 대답합니다.

1. std :: string보다 std :: wstring을 언제 사용해야합니까?

프로그래밍 플랫폼 또는 API 함수가 단일 바이트 함수이고 일부 유니 코드 데이터를 처리하거나 구문 분석하려는 경우 (예 : Windows'.REG 파일 또는 네트워크 2 바이트 스트림에서 읽음) std :: wstring 변수를 쉽게 선언해야합니다. 그들을 처리하십시오. 예 : wstring ws = L "中国 a"(6 옥텟 메모리 : 0x4E2D 0x56FD 0x0061), ws [0]을 사용하여 문자 '中'을, ws [1]을 사용하여 문자 '国'을 가져오고 ws [2]를 문자 'a'등을 얻습니다.

2. std :: string은 특수 문자를 포함하여 전체 ASCII 문자 세트를 보유 할 수 있습니까?

예. 그러나주의 : 미국 ASCII는 0x00 ~ 0xFF 8 진수가 각각 "123abc & * _ &"와 같은 인쇄 가능한 텍스트를 포함하여 한 문자를 나타내며 특수 문자는 대부분 '.'으로 인쇄한다는 의미입니다. 편집기 나 터미널을 혼동하지 마십시오. 그리고 일부 다른 국가에서는 자체의 "ASCII"문자 세트 (예 : 중국어)를 확장하여 한 문자를 나타 내기 위해 2 옥텟을 사용합니다.

3. std :: wstring은 널리 사용되는 모든 C ++ 컴파일러에서 지원됩니까?

아마, 또는 대부분. 나는 VC ++ 6과 GCC 3.3을 사용했다.

4. 정확히 "와이드 캐릭터"란 무엇입니까?

넓은 문자는 대부분 모든 국가의 문자를 담기 위해 2 옥텟 또는 4 옥텟을 사용함을 나타냅니다. 2 옥텟 UCS2는 대표적인 샘플이며, 예를 들어 영어 'a', 그 메모리는 2 옥텟의 0x0061입니다 (ASCII 'a의 메모리에서는 1 옥텟 0x61 임)


0

여기에는 매우 좋은 답변이 있지만 Windows / Visual Studio와 관련하여 추가 할 수있는 몇 가지가 있다고 생각합니다. Tis는 VS2015에 대한 나의 경험을 기반으로합니다. 리눅스에서는 기본적으로 std::string모든 곳에서 인코딩 된 UTF-8을 사용하는 것이 정답입니다 . Windows / VS에서는 더 복잡해집니다. 이유는 다음과 같습니다. Windows는 chars를 사용하여 저장된 문자열 이 로케일 코드 페이지를 사용하여 인코딩 될 것으로 예상 합니다. 이것은 거의 항상 ASCII 문자 집합이며 위치에 따라 128 개의 다른 특수 문자가옵니다. Windows API를 사용할 때뿐만 아니라 이러한 문자열이 표준 C ++와 상호 작용하는 다른 세 가지 주요 위치가 있음을 설명하겠습니다. 이들은 문자열 리터럴이며 파일 이름을 std::cout사용하여 <<에 전달합니다 std::fstream.

저는 언어 전문가가 아닌 프로그래머라는 점을 강조합니다. USC2와 UTF-16은 동일하지 않다는 점에 감사하지만 내 목적을 위해 그것들은 상호 교환이 가능하도록 여기에 가깝습니다. 실제로 어떤 Windows를 사용하는지 잘 모르겠지만 일반적으로 알 필요는 없습니다. 나는이 답변에 UCS2를 언급 했으므로이 문제에 대해 무지한 사람을 화나게하면 미리 죄송합니다. 문제가 있으면 기꺼이 변경하십시오.

문자열 리터럴

코드 페이지로 표현할 수있는 문자 만 포함하는 문자열 리터럴을 입력하면 VS는 코드 페이지를 기반으로 문자 인코딩 당 1 바이트로 파일에 저장합니다. 코드 페이지를 변경하거나 다른 코드 페이지를 사용하여 다른 개발자에게 소스를 제공하면 캐릭터가 다르게 끝날 것이라고 생각합니다 (그러나 테스트하지는 않았습니다). 다른 코드 페이지를 사용하여 컴퓨터에서 코드를 실행하면 문자가 변경되는지 확실하지 않습니다.

코드 페이지로 표현할 수없는 문자열 리터럴을 입력하면 VS가 파일을 유니 코드로 저장하도록 요청합니다. 그런 다음 파일은 UTF-8로 인코딩됩니다. 이는 모든 비 ASCII 문자 (코드 페이지에있는 문자 포함)가 2 바이트 이상으로 표시됨을 의미합니다. 즉, 다른 사람에게 소스를 제공하면 소스가 동일하게 보입니다. 그러나 소스를 컴파일러에 전달하기 전에 VS는 UTF-8로 인코딩 된 텍스트를 코드 페이지로 인코딩 된 텍스트로 변환하고 코드 페이지에서 누락 된 문자는로 바뀝니다 ?.

VS에서 유니 코드 문자열 리터럴을 올바르게 표현하는 유일한 방법은 문자열 리터럴 앞에 L넓은 문자열 리터럴을 만드는 것입니다. 이 경우 VS는 UTF-8로 인코딩 된 텍스트를 파일에서 UCS2로 변환합니다. 그런 다음이 문자열 리터럴을 std::wstring생성자 로 전달 하거나 utf-8로 변환하여에 배치해야합니다 std::string. 또는 Windows API 함수를 사용하여 코드 페이지를 사용하여 인코딩하여 코드를 넣을 수는 std::string있지만 넓은 문자열 리터럴을 사용하지 않았을 수도 있습니다.

std :: cout

사용하여 콘솔에 출력하는 경우 <<에만 사용할 수 std::string없습니다, std::wstring그리고 텍스트는 로케일 코드 페이지를 사용하여 인코딩해야합니다. 당신이 그렇다면 당신은 std::wstringWindows API 함수 중 하나를 사용하여 그것을 변환해야하며 코드 페이지에없는 문자 ?는 바뀔 것입니다 (문자를 변경할 수는 있지만 기억이 나지 않습니다).

std :: fstream 파일 이름

Windows OS는 파일 이름으로 UCS2 / UTF-16을 사용하므로 코드 페이지에 관계없이 모든 유니 코드 문자를 가진 파일을 가질 수 있습니다. 그러나 이는 코드 페이지에없는 문자를 사용하여 파일에 액세스하거나 파일을 만들려면 사용해야한다는 것을 의미합니다 std::wstring. 다른 방법은 없습니다. 이것은 Microsoft 고유의 확장 std::fstream이므로 다른 시스템에서는 컴파일되지 않을 것입니다. std :: string을 사용하면 코드 페이지에 문자 만 포함 된 파일 이름 만 사용할 수 있습니다.

당신의 옵션

만약 당신이 리눅스에서 일하고 있다면 아마도 이것을 얻지 못했을 것입니다. std::string어디서나 UTF-8을 사용하십시오 .

Windows에서 작업하는 경우 std::wstring어디에서나 UCS2를 사용하십시오 . 일부 순수 주의자들은 UTF8을 사용하고 필요할 때 변환한다고 말하지만 왜 번거롭지 않습니까?

크로스 플랫폼이라면 솔직하게 엉망입니다. Windows의 모든 곳에서 UTF-8을 사용하려고하면 문자열 리터럴을 조심하고 콘솔로 출력해야합니다. 거기에서 쉽게 현을 손상시킬 수 있습니다. std::wstringLinux의 모든 곳에서 사용 하는 경우 와이드 버전에 액세스 할 수 없으므로 std::fstream변환을 수행해야하지만 손상의 위험은 없습니다. 개인적으로 이것이 더 나은 옵션이라고 생각합니다. 많은 사람들이 동의하지 않지만, 나는 혼자가 아닙니다-예를 들어 wxWidgets가 취하는 경로입니다.

또 다른 옵션은 Linux 및 Windows에서와 unicodestring같이 typedef std::string를 사용하고 std::wstringUNI ()라는 매크로를 사용하여 Windows에서 L을 접두사로 사용하고 Linux에서는 아무것도 접두사를 갖지 않는 경우

#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>

#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
    std::string result;
    //Call WideCharToMultiByte to do the conversion
    return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
    return str;
}
#endif

int main()
{

    unicodestring fileName(UNI("fileName"));
    std::ofstream fout;
    fout.open(fileName);
    std::cout << formatForConsole(fileName) << std::endl;
    return 0;
}

내가 생각하는 어느 플랫폼에서나 괜찮을 것입니다.

대답

질문에 대답하려면

1) Windows에서 프로그래밍하는 경우 Windows에서 발생할 수있는 손상 문제를 처리하거나 #ifdefs차이점을 해결하기 위해 특정 플랫폼으로 코드를 작성하지 않는 한 항상 크로스 플랫폼 인 경우 항상 가능합니다. 리눅스는 절대 그런 적이 없다.

2) 그렇습니다. 또한 Linux에서는 모든 유니 코드에도 사용할 수 있습니다. Windows에서는 UTF-8을 사용하여 수동으로 인코딩하도록 선택한 경우 모든 유니 코드에 대해서만 사용할 수 있습니다. 그러나 Windows API 및 표준 C ++ 클래스는 std::string로캘 코드 페이지를 사용하여 인코딩 될 것으로 예상합니다 . 여기에는 컴퓨터가 사용하도록 설정 한 코드 페이지에 따라 변경되는 모든 ASCII와 다른 128자가 포함됩니다.

3) 나는 그렇게 생각하지만, 그렇지 않다면 wchar_t대신 'std :: basic_string'의 간단한 typedef입니다.char

4) 와이드 문자는 1 바이트 표준 char유형 보다 큰 문자 유형입니다 . Windows에서는 2 바이트이고 Linux에서는 4 바이트입니다.


1
"소스를 컴파일러에 전달하기 전에 VS는 UTF-8로 인코딩 된 텍스트를 코드 페이지로 인코딩 된 텍스트로 변환하고 코드 페이지에서 누락 된 문자는?로 바뀝니다." -> 컴파일러가 UTF-8 인코딩 (use /utf-8)을 사용할 때 이것이 사실이라고 생각하지 않습니다 .
Roi Danton

나는 이것을 옵션으로 몰랐다. 이 링크 docs.microsoft.com/en-us/cpp/build/reference/… 에서 프로젝트 속성에서 선택할 틱 상자가없는 것 같으 므로 추가 명령 줄 옵션으로 추가해야합니다. 좋은 자리!
Phil Rosenberg


-6

언제 와이드 문자를 사용해서는 안됩니까?

1990 년 이전에 코드를 작성할 때

분명히 나는 ​​뒤집어지고 있지만 실제로는 21 세기입니다. 그 이후로 127자는 충분하지 않았습니다. 예, UTF8을 사용할 수 있지만 왜 두통으로 귀찮게합니까?


16
@ dave : Widechars (UTF-16)보다 두통이 큰 UTF-8이 어떤 두통을 일으키는 지 모르겠습니다. UTF-16에서는 다중 문자 문자도 있습니다.
Pavel Radzivilovsky

문제는 영어권 국가 이외의 곳이라면 wchar_t를 사용해야한다는 것입니다. 말할 것도없이 일부 알파벳에는 바이트에 들어갈 수있는 것보다 더 많은 문자가 있습니다. 우리는 DOS에있었습니다. 코드 페이지 정신 분열증, 아니, 감사합니다, 더 이상 ..
스위프트-금요일 파이

1
@Swift 문제 wchar_t는 크기와 의미가 OS에 따라 다르다는 것 입니다. 기존 문제를 새로운 문제로 바꿉니다. 반면 a charcharOS와 무관합니다 (적어도 유사한 플랫폼에서). 따라서 UTF-8을 사용하고 모든 것을 시퀀스로 char묶고 C ++이 이러한 시퀀스 내에서 측정, 색인화, 찾기 등의 표준 방법없이 어떻게 우리 자신을 완전히 떠나게하는지 애도 할 수 있습니다.
underscore_d

1
@Swift 당신은 그것을 완전히 거꾸로 한 것 같습니다. wchar_t는 고정 너비 데이터 형식이므로 10의 배열 wchar_t은 항상 sizeof(wchar_t) * 10플랫폼 바이트를 차지 합니다. UTF-16은 문자가 1 또는 2 개의 16 비트 코드 포인트 (UTF-8의 경우 s / 16 / 8 / g)로 구성 될 수있는 가변 폭 인코딩입니다.
underscore_d

1
@SteveHollasch Windows에서 문자열의 wchar_t 표현은 특수 대리 쌍으로 FFFF보다 큰 문자를 인코딩하고 다른 하나는 wchar_t 요소를 하나만 사용합니다. 따라서 표현은 gnu 컴파일러에 의해 생성 된 표현과 호환되지 않습니다 (FFFF 미만의 모든 문자 앞에는 0 개의 단어가 있음). wchar_t에 저장된 내용은 프로그래머와 컴파일러에 의해 결정되며 일부 계약에 따라 결정되지 않습니다.
Swift-Friday Pie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.