programing tip

std :: wstring VS std :: string

itbloger 2020. 9. 30. 08:52
반응형

std :: wstring VS std :: string


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

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

string? wstring?

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

charwchar_t

char일반적으로 8 비트 문자 인 문자를 보유해야합니다.
wchar_t와이드 문자를 포함해야하는데 문제가 발생합니다.
Linux에서 a wchar_t는 4 바이트이고 Windows에서는 2 바이트입니다.

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

문제는 어느 char것도 wchar_t유니 코드에 직접 연결되어 있지 않다는 것 입니다.

Linux에서?

Linux OS를 살펴 보겠습니다. 내 Ubuntu 시스템은 이미 유니 코드를 인식하고 있습니다. 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의 4 개의 문자로 구성되어 있음을 알 수 있습니다 (후행 0은 계산하지 않음). ( wchar_t연습으로 코드 를 공부하도록하겠습니다 )

따라서 charLinux에서 작업 할 때 일반적으로 알지 못하는 사이에 유니 코드를 사용해야합니다. 와 함께 std::string작동 char하므로 std::string이미 유니 코드를 사용할 수 있습니다.

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

Windows에서?

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

그래서 그들의 솔루션은 흥미로운 것입니다. 응용 프로그램이에서 작동하는 char경우 char 문자열은 시스템의 로컬 문자 집합 / 코드 페이지를 사용하여 GUI 레이블에 인코딩 / 인쇄 / 표시됩니다. 예를 들어, "olé"는 프랑스어로 지역화 된 Windows에서는 "olé"이지만 키릴 문자로 지역화 된 Windows에서는 다른 것입니다 ( Windows-1251 을 사용하는 경우 "olй" ). 따라서 "이전 앱"은 일반적으로 이전 방식과 동일하게 작동합니다.

유니 코드 기반 응용 프로그램의 경우 Windows wchar_t는 2 바이트 너비이고 2 바이트 문자 (또는 최소한 거의 호환되는 UCS-2 )로 인코딩 된 UTF-16으로 인코딩 된을 사용합니다. 같은 IIRC).

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

따라서 Windows에서 작업하는 경우 사용 하고 싶을 것입니다 wchar_t( GTK + 또는 QT 와 같은 프레임 워크를 숨기지 않는 한 ). 사실 Windows는 뒤에서 wchar_t문자열로 작동 하므로 이전 응용 프로그램에서도 API charwchar_t사용할 때 문자열이 변환됩니다 SetWindowText()(Win32 GUI에서 레이블을 설정하는 저수준 API 기능).

메모리 문제?

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

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

그래도 다른 언어 (중국어, 일본어 등)의 경우 사용되는 메모리는 UTF-16과 동일하거나 UTF-8의 경우 약간 더 큽니다.

대체로 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을 사용해야합니까?

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

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

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

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

    Linux에서? 예.
    Windows에서? Windows 사용자의 현재 로케일에 사용할 수있는 특수 문자 만 있습니다.

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

    1. ASCII는 0에서 127로 이동해야합니다. 더 높은 chars는 ASCII가 아닙니다.
    2. a char from 0 to 127 will be held correctly
    3. a char from 128 to 255 will have a signification depending on your encoding (unicode, non-unicode, etc.), but it will be able to hold all Unicode glyphs as long as they are encoded in UTF-8.
  3. Is std::wstring supported by almost all popular C++ compilers?

    Mostly, with the exception of GCC based compilers that are ported to Windows.
    It works on my g++ 4.3.2 (under Linux), and I used Unicode API on Win32 since Visual C++ 6.

  4. What is exactly a wide character?

    On C/C++, it's a character type written wchar_t which is larger than the simple char character type. It is supposed to be used to put inside characters whose indices (like Unicode glyphs) are larger than 255 (or 127, depending...).


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

내 견해는 내가 공동 저자 인 http://utf8everywhere.org요약되어 있습니다 .

응용 프로그램이 API 호출 중심 (예 : 주로 UI 응용 프로그램)이 아닌 경우 유니 코드 문자열을 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의 문자는 한 쌍 또는 두 쌍을 취합니다.

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

내 실용적인 결론은 놀랍도록 간단합니다. C ++ (및 STL) "문자 인코딩"항목은 모두 실질적으로 손상되고 쓸모가 없습니다. 어쨌든 도움이되지 않을 것입니다.

내 해결책은 심층 조사 후 많은 좌절감과 그에 따른 경험입니다.

  1. 인코딩 및 변환 작업에 대한 책임은 자신에게 있음을 인정합니다 (대부분이 다소 사소하다는 것을 알게 될 것입니다).

  2. UTF-8로 인코딩 된 문자열에 std :: string을 사용합니다 (단지 typedef std::string UTF8String)

  3. 그러한 UTF8String 객체는 멍청하지만 값싼 컨테이너라는 것을 받아들이십시오. 문자에 직접 액세스하거나 조작하지 마십시오 (검색, 바꾸기 등 없음). 할 수는 있지만 실제로는 멀티 바이트 문자열에 대한 텍스트 조작 알고리즘을 작성하는 데 시간을 낭비하고 싶지 않습니다! 다른 사람들이 이미 그런 멍청한 짓을했다고해도 그렇게하지 마세요! 순리에 맡기다! (글쎄, 그럴듯한 시나리오가 있습니다 ... 그저 ICU 라이브러리를 사용하십시오).

  4. use std::wstring for UCS-2 encoded strings (typedef std::wstring UCS2String) - this is a compromise, and a concession to the mess that the WIN32 API introduced). UCS-2 is sufficient for most of us (more on that later...).

  5. use UCS2String instances whenever a character-by-character access is required (read, manipulate, and so on). Any character-based processing should be done in a NON-multibyte-representation. It is simple, fast, easy.

  6. add two utility functions to convert back & forth between UTF-8 and UCS-2:

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

The conversions are straightforward, google should help here ...

That's it. Use UTF8String wherever memory is precious and for all UTF-8 I/O. Use UCS2String wherever the string must be parsed and/or manipulated. You can convert between those two representations any time.

Alternatives & Improvements

  • conversions from & to single-byte character encodings (e.g. ISO-8859-1) can be realized with help of plain translation tables, e.g. const wchar_t tt_iso88951[256] = {0,1,2,...}; and appropriate code for conversion to & from UCS2.

  • if UCS-2 is not sufficient, than switch to UCS-4 (typedef std::basic_string<uint32_t> UCS2String)

ICU or other unicode libraries?

For advanced stuff.


  1. When you want to have wide characters stored in your string. wide depends on the implementation. Visual C++ defaults to 16 bit if i remember correctly, while GCC defaults depending on the target. It's 32 bits long here. Please note wchar_t (wide character type) has nothing to do with unicode. It's merely guaranteed that it can store all the members of the largest character set that the implementation supports by its locales, and at least as long as char. You can store unicode strings fine into std::string using the utf-8 encoding too. But it won't understand the meaning of unicode code points. So str.size() won't give you the amount of logical characters in your string, but merely the amount of char or wchar_t elements stored in that string/wstring. For that reason, the gtk/glib C++ wrapper folks have developed a Glib::ustring class that can handle utf-8.

    If your wchar_t is 32 bits long, then you can use utf-32 as an unicode encoding, and you can store and handle unicode strings using a fixed (utf-32 is fixed length) encoding. This means your wstring's s.size() function will then return the right amount of wchar_t elements and logical characters.

  2. Yes, char is always at least 8 bit long, which means it can store all ASCII values.
  3. Yes, all major compilers support it.

I frequently use std::string to hold utf-8 characters without any problems at all. I heartily recommend doing this when interfacing with API's which use utf-8 as the native string type as well.

For example, I use utf-8 when interfacing my code with the Tcl interpreter.

The major caveat is the length of the std::string, is no longer the number of characters in the string.


  1. When you want to store 'wide' (Unicode) characters.
  2. Yes: 255 of them (excluding 0).
  3. Yes.
  4. Here's an introductory article: http://www.joelonsoftware.com/articles/Unicode.html

Applications that are not satisfied with only 256 different characters have the options of either using wide characters (more than 8 bits) or a variable-length encoding (a multibyte encoding in C++ terminology) such as UTF-8. Wide characters generally require more space than a variable-length encoding, but are faster to process. Multi-language applications that process large amounts of text usually use wide characters when processing the text, but convert it to UTF-8 when storing it to disk.

The only difference between a string and a wstring is the data type of the characters they store. A string stores chars whose size is guaranteed to be at least 8 bits, so you can use strings for processing e.g. ASCII, ISO-8859-15, or UTF-8 text. The standard says nothing about the character set or encoding.

Practically every compiler uses a character set whose first 128 characters correspond with ASCII. This is also the case with compilers that use UTF-8 encoding. The important thing to be aware of when using strings in UTF-8 or some other variable-length encoding, is that the indices and lengths are measured in bytes, not characters.

The data type of a wstring is wchar_t, whose size is not defined in the standard, except that it has to be at least as large as a char, usually 16 bits or 32 bits. wstring can be used for processing text in the implementation defined wide-character encoding. Because the encoding is not defined in the standard, it is not straightforward to convert between strings and wstrings. One cannot assume wstrings to have a fixed-length encoding either.

If you don't need multi-language support, you might be fine with using only regular strings. On the other hand, if you're writing a graphical application, it is often the case that the API supports only wide characters. Then you probably want to use the same wide characters when processing the text. Keep in mind that UTF-16 is a variable-length encoding, meaning that you cannot assume length() to return the number of characters. If the API uses a fixed-length encoding, such as UCS-2, processing becomes easy. Converting between wide characters and UTF-8 is difficult to do in a portable way, but then again, your user interface API probably supports the conversion.


  1. when you want to use Unicode strings and not just ascii, helpful for internationalisation
  2. yes, but it doesn't play well with 0
  3. not aware of any that don't
  4. wide character is the compiler specific way of handling the fixed length representation of a unicode character, for MSVC it is a 2 byte character, for gcc I understand it is 4 bytes. and a +1 for http://www.joelonsoftware.com/articles/Unicode.html

1) As mentioned by Greg, wstring is helpful for internationalization, that's when you will be releasing your product in languages other than english

4) Check this out for wide character http://en.wikipedia.org/wiki/Wide_character


There are some very good answers here, but I think there are a couple of things I can add regarding Windows/Visual Studio. Tis is based on my experience with VS2015. On Linux, basically the answer is to use UTF-8 encoded std::string everywhere. On Windows/VS it gets more complex. Here is why. Windows expects strings stored using chars to be encoded using the locale codepage. This is almost always the ASCII character set followed by 128 other special characters depending on your location. Let me just state that this in not just when using the Windows API, there are three other major places where these strings interact with standard C++. These are string literals, output to std::cout using << and passing a filename to std::fstream.

I will be up front here that I am a programmer, not a language specialist. I appreciate that USC2 and UTF-16 are not the same, but for my purposes they are close enough to be interchangeable and I use them as such here. I'm not actually sure which Windows uses, but I generally don't need to know either. I've stated UCS2 in this answer, so sorry in advance if I upset anyone with my ignorance of this matter and I'm happy to change it if I have things wrong.

String literals

If you enter string literals that contain only characters that can be represented by your codepage then VS stores them in your file with 1 byte per character encoding based on your codepage. Note that if you change your codepage or give your source to another developer using a different code page then I think (but haven't tested) that the character will end up different. If you run your code on a computer using a different code page then I'm not sure if the character will change too.

If you enter any string literals that cannot be represented by your codepage then VS will ask you to save the file as Unicode. The file will then be encoded as UTF-8. This means that all Non ASCII characters (including those which are on your codepage) will be represented by 2 or more bytes. This means if you give your source to someone else the source will look the same. However, before passing the source to the compiler, VS converts the UTF-8 encoded text to code page encoded text and any characters missing from the code page are replaced with ?.

The only way to guarantee correctly representing a Unicode string literal in VS is to precede the string literal with an L making it a wide string literal. In this case VS will convert the UTF-8 encoded text from the file into UCS2. You then need to pass this string literal into a std::wstring constructor or you need to convert it to utf-8 and put it in a std::string. Or if you want you can use the Windows API functions to encode it using your code page to put it in a std::string, but then you may as well have not used a wide string literal.

std::cout

When outputting to the console using << you can only use std::string, not std::wstring and the text must be encoded using your locale codepage. If you have a std::wstring then you must convert it using one of the Windows API functions and any characters not on your codepage get replaced by ? (maybe you can change the character, I can't remember).

std::fstream filenames

Windows OS uses UCS2/UTF-16 for its filenames so whatever your codepage, you can have files with any Unicode character. But this means that to access or create files with characters not on your codepage you must use std::wstring. There is no other way. This is a Microsoft specific extension to std::fstream so probably won't compile on other systems. If you use std::string then you can only utilise filenames that only include characters on your codepage.

Your options

If you are just working on Linux then you probably didn't get this far. Just use UTF-8 std::string everywhere.

If you are just working on Windows just use UCS2 std::wstring everywhere. Some purists may say use UTF8 then convert when needed, but why bother with the hassle.

If you are cross platform then it's a mess to be frank. If you try to use UTF-8 everywhere on Windows then you need to be really careful with your string literals and output to the console. You can easily corrupt your strings there. If you use std::wstring everywhere on Linux then you may not have access to the wide version of std::fstream, so you have to do the conversion, but there is no risk of corruption. So personally I think this is a better option. Many would disagree, but I'm not alone - it's the path taken by wxWidgets for example.

Another option could be to typedef unicodestring as std::string on Linux and std::wstring on Windows, and have a macro called UNI() which prefixes L on Windows and nothing on Linux, then the code

#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;
}

would be fine on either platform I think.

Answers

So To answer your questions

1) If you are programming for Windows, then all the time, if cross platform then maybe all the time, unless you want to deal with possible corruption issues on Windows or write some code with platform specific #ifdefs to work around the differences, if just using Linux then never.

2)Yes. In addition on Linux you can use it for all Unicode too. On Windows you can only use it for all unicode if you choose to manually encode using UTF-8. But the Windows API and standard C++ classes will expect the std::string to be encoded using the locale codepage. This includes all ASCII plus another 128 characters which change depending on the codepage your computer is setup to use.

3)I believe so, but if not then it is just a simple typedef of a 'std::basic_string' using wchar_t instead of char

4)A wide character is a character type which is bigger than the 1 byte standard char type. On Windows it is 2 bytes, on Linux it is 4 bytes.


A good question! I think DATA ENCODING (sometimes a CHARSET also involved) is a MEMORY EXPRESSION MECHANISM in order to save data to a file or transfer data via a network, so I answer this question as:

1. When should I use std::wstring over std::string?

If the programming platform or API function is a single-byte one, and we want to process or parse some Unicode data, e.g read from Windows'.REG file or network 2-byte stream, we should declare std::wstring variable to easily process them. e.g.: wstring ws=L"中国a"(6 octets memory: 0x4E2D 0x56FD 0x0061), we can use ws[0] to get character '中' and ws[1] to get character '国' and ws[2] to get character 'a', etc.

2. Can std::string hold the entire ASCII character set, including the special characters?

Yes. But notice: American ASCII, means each 0x00~0xFF octet stands for one character, including printable text such as "123abc&*_&" and you said special one, mostly print it as a '.' avoid confusing editors or terminals. And some other countries extend their own "ASCII" charset, e.g. Chinese, use 2 octets to stand for one character.

3.Is std::wstring supported by all popular C++ compilers?

Maybe, or mostly. I have used: VC++6 and GCC 3.3, YES

4. What is exactly a "wide character"?

a wide character mostly indicates using 2 octets or 4 octets to hold all countries' characters. 2 octet UCS2 is a representative sample, and further e.g. English 'a', its memory is 2 octet of 0x0061(vs in ASCII 'a's memory is 1 octet 0x61)


When should you NOT use wide-characters?

When you're writing code before the year 1990.

Obviously, I'm being flip, but really, it's the 21st century now. 127 characters have long since ceased to be sufficient. Yes, you can use UTF8, but why bother with the headaches?

참고URL : https://stackoverflow.com/questions/402283/stdwstring-vs-stdstring

반응형