std :: wstring VS std :: string

我无法理解std::stringstd::wstring之间的区别。 我知道wstring支持宽字符,如Unicode字符。 我有以下问题:

  • 什么时候应该使用std::wstring不是std::string
  • std::string保存整个ASCII字符集,包括特殊字符吗?
  • 所有流行的C ++编译器都支持std::wstring吗?
  • 什么是“宽字符”?

  • stringwstring

    std::string是在char上模板化的basic_string ,在wchar_t上是std::wstring

    charwchar_t

    char应该包含一个字符,通常是1个字节的字符。 wchar_t应该保持宽字符,然后,事情变得棘手:在Linux上, wchar_t是4个字节,而在Windows上,它是2个字节

    那么Unicode呢呢?

    问题是charwchar_t都不直接绑定到unicode。

    在Linux上?

    让我们来看一个Linux操作系统:我的Ubuntu系统已经知道了unicode。 当我使用char字符串时,它本地编码为UTF-8(即字符串的Unicode字符串)。 以下代码:

    #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(bytes)     :" ;
    
       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(bytes)    :" ;
    
       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(bytes)     : 111 108 195 169
    
    sizeof(wchar_t) : 4
    wtext           : UNABLE TO CONVERT NATIVELY.
    wtext           : ol�
    sizeof(wtext)   : 16
    wcslen(wtext)   : 3
    wtext(bytes)    : 111 108 233
    

    你会看到char的“olé”文本是由四个字符构成的:110,108,195和169(不包括结尾的零)。 (我会让你学习wchar_t代码作为练习)

    所以,在Linux上使用char时,通常应该在不知道它的情况下使用Unicode。 由于std :: string与char一起工作,所以std :: string已经准备好了。

    请注意,std :: string与C字符串API一样,会认为“olé”字符串有4个字符,而不是3个字符。 所以在截断/播放unicode字符时应该小心谨慎,因为在UTF-8中禁止使用某些字符组合。

    在Windows上?

    在Windows上,这有点不同。 在Unicode出现之前,Win32必须支持大量的应用程序,使用char和全世界生成的不同字符集/代码页。

    所以他们的解决方案非常有趣:如果应用程序使用char ,那么char字符串将使用本地字符集/代码页在机器上编码/打印/显示在GUI标签上。 例如,“olé”在法语本地化的Windows中将是“olé”,但在西里尔语本地化的Windows上(如果使用Windows-1251,则为“olé”)。 因此,“历史应用程序”通常仍然以旧的方式工作。

    对于基于Unicode的应用程序,Windows使用宽度为2个字节的wchar_t ,并以UTF-16编码,该编码采用2字节字符的Unicode编码(或者至少是大多数兼容的UCS-2,这几乎是同样的事情IIRC)。

    使用char应用程序被称为“多字节”(因为每个字形都由一个或多个char组成),而使用wchar_t应用程序称为“widechar”(因为每个字形都由一个或两个wchar_t 。请参阅MultiByteToWideChar和WideCharToMultiByte Win32转换API获取更多信息。

    因此,如果你在Windows上工作,你很想使用wchar_t (除非你使用隐藏GTK +或QT的框架)。 事实是,在幕后,Windows配合使用wchar_t字符串,因此,即使历史的应用也会有他们的char在转换字符串wchar_t使用像SetWindowText函数API时(低级别API函数来设置标签上一个Win32 GUI)。

    内存问题?

    UTF-32每个字符4个字节,因此没有太多要添加的内容,只要UTF-8文本和UTF-16文本总是使用少于或等于UTF-32文本的内存量(通常较少)。

    如果存在内存问题,那么您应该比大多数西方语言知道,UTF-8文本将使用比相同的UTF-16更少的内存。

    尽管如此,对于其他语言(中文,日文等),所使用的内存将相同,或者对于UTF-8比UTF-16更大。

    总而言之,UTF-16将主要使用每个字符2个字节(除非你正在处理某种深奥的语言符号(Klingon?Elvish?),而UTF-8将花费1到4个字节。

    有关更多信息,请参见http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16。

    结论

    1.当我应该使用std :: wstring over std :: string?

    在Linux上? 几乎从不 (§)。
    在Windows上? 几乎总是 (§)。
    在跨平台的代码? 取决于你的工具包...

    (§):除非您使用工具包/框架否则

    2. std :: string是否可以保存包含特殊字符的所有ASCII字符集?

    注意:std :: string适用于存放'binary'缓冲区,其中std :: wstring不是!

    在Linux上? 是。
    在Windows上? 只有Windows用户的当前语言环境可用的特殊字符。

    编辑(在来自Johann Gerell的评论之后):std :: string将足以处理所有基于char的字符串(每个char是从0到255的数字)。 但:

  • ASCII应该从0到127.更高的字符不是ASCII。
  • 从0到127的字符将被正确保存
  • 从128到255的字符将取决于您的编码(unicode,非unicode等),但是只要它们使用UTF-8编码,就可以保存所有Unicode字形。
  • 3.几乎所有流行的C ++编译器都支持std :: wstring吗?

    大多数情况下,除了基于GCC的编译器移植到Windows之外
    它适用于我的g ++ 4.3.2(在Linux下),并且自从Visual C ++ 6开始在Win32上使用Unicode API。

    4.什么是宽字符?

    在C / C ++上,它是一个写入wchar_t的字符类型,它比简单的char字符类型更大。 它应该用于放置其索引(如Unicode字形)大于255(或127,取决于...)的字符。


    我建议在Windows或其他地方避免使用std::wstring ,除非接口要求或Windows API调用附近的任何位置以及各自的编码转换作为语法糖。

    我的观点总结在http://utf8everywhere.org,其中我是合着者。

    除非您的应用程序是以API为中心的,例如主要是UI应用程序,否则建议将Unicode字符串存储在std :: string中,并以UTF-8编码,在API调用附近执行转换。 文章中概述的好处胜过转换的明显烦恼,特别是在复杂的应用程序中。 对于多平台和图书馆开发来说这是双重的。

    现在,回答你的问题:

  • 有几个薄弱的原因。 它的存在是出于历史原因,宽广的人被认为是支持Unicode的正确方式。 现在它被用来连接喜欢UTF-16字符串的API。 我只在这些API调用的直接附近使用它们。
  • 这与std :: string无关。 它可以容纳你输入的任何编码。 唯一的问题是如何对待它的内容。 我的建议是UTF-8,所以它能够正确保存所有的Unicode字符。 这是Linux上的常见做法,但我认为Windows程序也应该这样做。
  • 没有。
  • 宽字符是一个令人困惑的名字。 在Unicode的早期阶段,人们相信字符可以用两个字节编码,因此也就是名称。 今天,它代表“字节长度为两个字节的任何部分”。 UTF-16被看作是这种字节对的序列(又名宽字符)。 UTF-16中的字符需要一对或两对。

  • 所以,这里的每个读者现在都应该清楚地了解事实和情况。 如果没有,那么你必须阅读paercebal的杰出全面的答案 [顺便说一句:谢谢!]。

    我的实用结论非常简单:所有C ++(和STL)“字符编码”的东西实质上已经被破坏和无用。 把它归咎于微软或没有,这无济于事。

    经过深入调查后,我的解决方案经历了许多挫折和相应的经验:

  • 接受,你必须自己负责编码和转换的东西(你会看到它的很多都是微不足道的)

  • 对任何UTF-8编码的字符串使用std :: string(只是一个typedef std::string UTF8String

  • 接受这样一个UTF8String对象只是一个愚蠢的,但便宜的容器。 永远不要直接访问和/或操作字符(不搜索,替换等)。 你可以,但你真的只是真的,真的不想浪费时间为多字节字符串编写文本操作算法! 即使其他人已经做了这种愚蠢的事情,不要这样做! 随它去! (好吧,有些情况下它是有道理的......只是使用那些ICU库)。

  • 对于UCS-2编码的字符串使用std :: wstring( typedef std::wstring UCS2String ) - 这是一种妥协,并且是对WIN32 API引入的混乱的让步)。 UCS-2对于我们大多数人来说已经足够了(更多关于......)。

  • 每当需要逐个字符的访问时使用UCS2String实例(读取,操作等)。 任何基于字符的处理应该以非多字节表示方式完成。 它很简单,快速,简单。

  • 添加两个实用函数来在UTF-8和UCS-2之间来回转换:

    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );
    
  • 转换很简单,谷歌应该在这里帮助...

    而已。 使用UTF8String,无论内存是珍贵的还是适用于所有UTF-8 I / O。 无论何处必须解析和/或操纵字符串,都使用UCS2String。 您可以随时在这两种表示之间进行转换。

    替代品和改进

  • 可以在普通转换表的帮助下实现从&到单字节字符编码(例如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或其他unicode库?

    先进的东西。

    链接地址: http://www.djcxy.com/p/5055.html

    上一篇: std::wstring VS std::string

    下一篇: using std::<type> v.s. using std namespace