关于c ++:std :: wstring VS std :: string

std::wstring VS std::string

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

  • 我什么时候应该使用std::wstring而不是std::string
  • std::string能否保存整个ASCII字符集,包括特殊字符?
  • EDCOX1?1是由所有流行的C++编译器支持的吗?
  • 什么才是"宽性格"?

  • EDOCX1?0?EDOCX1?1?

    std::string是在char上模板化的basic_string,在wchar_t上模板化的std::wstring。好的。charwchar_t的比较

    char应该包含一个字符,通常是一个8位字符。wchar_t应该具有广泛的特点,然后事情变得复杂起来:在Linux上,wchar_t是4个字节,而在Windows上是2个字节。好的。那Unicode呢?

    问题是,charwchar_t都不是直接与unicode联系在一起的。好的。在Linux上?

    以Linux操作系统为例:我的Ubuntu系统已经支持Unicode。当我使用char字符串时,它是以utf-8(即unicode字符字符串)进行本机编码的。以下代码:好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    #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;
    }

    输出以下文本:好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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

    您将看到char中的"ol_"文本实际上由四个字符构成:110、108、195和169(不包括尾随的零)。(我让你把wchar_t代码作为练习来学习)好的。

    因此,在Linux上使用char时,您通常会在不知道的情况下使用Unicode。由于std::stringchar一起工作,所以std::string已经可以使用Unicode了。好的。

    注意,与C字符串API一样,std::string将认为"ol_"字符串有4个字符,而不是3个字符。因此,在截断/播放Unicode字符时应该谨慎,因为在UTF-8中禁止某些字符组合。好的。在Windows上?

    在Windows上,这有点不同。在unicode出现之前,win32必须支持许多与char和世界上生产的不同字符集/代码页一起工作的应用程序。好的。

    所以他们的解决方案是一个有趣的解决方案:如果一个应用程序与char一起工作,那么char字符串将使用机器上的本地charset/codepage编码/打印/显示在GUI标签上。例如,"ol_"在法文本地化的窗口中是"ol_",但在西里尔文本地化的窗口(如果使用Windows-1251,则为"ol_")上则有所不同。因此,"历史应用程序"的工作方式通常还是老样子。好的。

    对于基于Unicode的应用程序,Windows使用2字节宽的wchar_t,并用utf-16编码,utf-16是Unicode编码的2字节字符(或者至少是最兼容的ucs-2,几乎与iirc相同)。好的。

    使用char的应用程序称为"多字节"(因为每个glyph由一个或多个chars组成),而使用wchar_t的应用程序称为"宽字符"(因为每个glyph由一个或两个wchar_t组成)。有关详细信息,请参阅MultiByteToWideChar和WideChartoMultiByte Win32转换API。好的。

    因此,如果您在Windows上工作,您非常希望使用wchar_t(除非您使用一个隐藏它的框架,如gtk+或qt…)。事实是,在幕后,Windows与wchar_t字符串一起工作,因此即使是历史应用程序,在使用类似于SetWindowText()的API(低级API函数在win32 GUI上设置标签)时,也会将其char字符串转换为wchar_t。好的。内存问题?

    UTF-32是每个字符4个字节,因此没有什么可添加的,只要一个UTF-8文本和UTF-16文本总是比一个UTF-32文本使用更少或相同的内存量(通常更少)。好的。

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

    不过,对于其他语言(中文、日文等),使用的内存将与UTF-8相同,或者略大于UTF-16。好的。

    总而言之,UTF-16通常每个字符使用2个字节,有时使用4个字节(除非您正在处理某种深奥的语言符号(Klingon?精灵?),而utf-8将花费1到4个字节。好的。

    有关详细信息,请参阅http://en.wikipedia.org/wiki/utf-8 compared to utf-16。好的。结论

  • 什么时候应该在std::string上使用std::wstring?好的。

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

    (§):除非使用工具箱/框架,否则好的。

  • std::string是否可以保存所有的ASCII字符集,包括特殊字符?好的。

    注意:std::string适用于保存"二进制"缓冲区,而std::wstring不适用于这种缓冲区!好的。

    在Linux上?对。在Windows上?只有特殊字符可用于Windows用户的当前区域设置。好的。

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

  • ASCII应该从0到127。较高的chars不是ASCII码。
  • 从0到127的char将正确保持。
  • 从128到255的char将根据编码(Unicode、非Unicode等)有意义,但只要用UTF-8编码,它就能够保存所有Unicode标志符号。
  • 几乎所有流行的C++编译器都支持EDCOX1 7吗?好的。

    大多数情况下,除了移植到Windows的基于GCC的编译器。它在我的G+4.4.2(Linux下)工作,我在VisualC++ 6上使用了Win32上的Unicode API。好的。

  • 什么是宽字符?好的。

    在C/C++上,它是一个EDCOX1×0的字符类型,它比简单的EDCOX1×2字符类型大。它应该用于放置索引(如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非常全面的答案[btw:谢谢!]

    我的实用主义结论很简单:所有的C++(和STL)字符编码"实质上是破碎的和无用的"。不管是否归咎于微软,这也无济于事。

    我的解决方案是,经过深入的调查,很多挫折和相应的经验如下:

  • 接受,你必须自己负责编码和转换的工作(你会发现大部分工作都很琐碎)

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

  • 接受这样一个utf8string对象只是一个愚蠢但廉价的容器。永远不要直接访问和/或操作其中的字符(不搜索、替换等)。你可以,但你真的只是真的,真的不想浪费时间为多字节字符串编写文本操作算法!即使其他人已经做了这么愚蠢的事情,也不要这样做!顺其自然!(好吧,有些场景是有意义的……只需使用ICU图书馆。

  • 对ucs-2编码字符串使用std::wstring(typedef std::wstring UCS2String)——这是一种折衷,是对win32 API引入的混乱局面的让步。UCS-2对我们大多数人来说已经足够了(稍后会有更多的讨论…)。

  • 只要需要逐字符访问(读取、操作等),就使用UCS2字符串实例。任何基于字符的处理都应该在非多字节表示中完成。它简单、快速、简单。

  • 添加两个实用程序函数以在utf-8和ucs-2之间来回转换:

    1
    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 UCS2String)

    ICU或其他Unicode库?

    先进的东西。


  • 当你想有你的字符串存储在宽的特点。widedepends on the implementation。的Visual C + + defaults to 16位如果我记得正确,depending on the defaults全球目标。这里是32位长。Please笔记_ wchar t(宽character has to do with型)没有Unicode。这是我的商店,它merely移调the members of the character set the implementation supports为最大,其地点和模式,至少只要字符。你可以使用Unicode字符串的结束std::stringstore into the encoding utf-8太。但它不会明白the meaning of Unicode代码点。我不会给你str.size()the amount of your characters在逻辑串,but the amount of merely wchar t的字符或字符串_元/ wstring stored in that。for that reason,茶/ glib GTK开发的C + +类,有人在wrapper Glib::ustringthat can handle utf - 8。P></

    如果你_ wchar t是32位长,那么你可以使用Unicode编码utf-32as an和商店,你可以使用Unicode字符串和handle(UTF - 32是固定的固定长度编码)。这将你的wstring'均值S函数然后返回s.size()wchar t the right amount of characters _布尔逻辑元素。P></

  • 是的,我总是8位字符长least is which可以在商店,它的ASCII值的均值。
  • 是的,在专业compilers EN支持。

  • 性病::字符串的竞相使用UTF-8 characters to hold without any问题在所有。我做的heartily recommend interfacing with which this api' S使用UTF-8字符串as as the原生型阱。P></

    for example,当我使用UTF-8 interfacing with the TCL interpreter队列。P></

    专业商品is the length of the性病::字符串,is the number of characters周不在字符串。P></


  • 当你想在商店(Unicode)宽的特点。
  • 是:(excluding 0 255 of them)。
  • 是的。
  • 这是一条introductory:http:////unicode.html www.joelonsoftware.com文章

  • 不满足于256个不同字符的应用程序可以使用宽字符(大于8位)或可变长度编码(在C++术语中的多字节编码),如UTF-8。宽字符通常比可变长度编码需要更多的空间,但处理速度更快。处理大量文本的多语言应用程序在处理文本时通常使用宽字符,但在将文本存储到磁盘时将其转换为UTF-8。

    stringwstring之间的唯一区别是它们存储的字符的数据类型。字符串存储chars,其大小保证至少为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可能支持这种转换。


  • 当你想使用ASCII和Unicode字符串internationalisation not just for,帮助
  • 是的,但它不好用。0
  • not any of that不感知
  • 宽character is the of the Way编译器处理固定长度的特异性表现在Unicode字符,其中en is for 2字节字符,它是了解顾客的为4个字节。和+ 1)http:////unicode.html www.joelonsoftware.com文章

  • 这里有一些很好的答案,但我认为关于Windows/Visual Studio,我可以添加一些东西。这是基于我对VS2015的经验。在Linux上,答案基本上是到处使用UTF-8编码的std::string。在windows/vs上,它变得更加复杂。这就是原因。Windows希望使用char存储的字符串使用区域设置代码页进行编码。这几乎总是ASCII字符集,后面跟着128个其他特殊字符,具体取决于您的位置。让我陈述这一点,不仅仅是在使用Windows API时,还有三个主要的地方,这些字符串与标准C++交互。这些是字符串文本,使用<<输出到std::cout并向std::fstream传递文件名。好的。

    我将站在前面,我是一个程序员,而不是语言专家。我很感激USC2和UTF-16不一样,但就我的目的而言,它们非常接近,可以互换,我在这里就是这样使用的。我实际上不确定哪些窗口使用,但我一般也不需要知道。我已经在这个答案中说明了UCS2,所以如果我对这个问题的无知使任何人感到不安,那么我提前道歉,如果我有什么问题,我很乐意改变它。好的。字符串常量

    如果您输入的字符串文本只包含代码页可以表示的字符,那么VS会将它们存储在您的文件中,并根据代码页对每个字符编码1个字节。请注意,如果您更改代码页或将源代码提供给使用不同代码页的其他开发人员,那么我认为(但尚未测试)字符最终会有所不同。如果您在使用不同代码页的计算机上运行代码,那么我不确定字符是否也会更改。好的。

    如果您输入了任何不能由代码页表示的字符串文本,那么vs将要求您将文件保存为unicode。然后文件将被编码为UTF-8。这意味着所有非ASCII字符(包括代码页上的字符)将由2个或更多字节表示。这意味着如果将源代码提供给其他人,则源代码将看起来相同。但是,在将源代码传递给编译器之前,vs将utf-8编码文本转换为代码页编码文本,代码页中缺少的任何字符都将替换为?。好的。

    确保在vs中正确表示unicode字符串文字的唯一方法是在字符串文字前面加上L,使其成为宽字符串文字。在这种情况下,VS会将文件中的UTF-8编码文本转换为UCS2。然后需要将这个字符串文字传递到std::wstring构造函数中,或者需要将其转换为utf-8并将其放入std::string中。或者,如果您想使用Windows API函数来编码它,可以使用代码页将其放入std::string中,但也可以不使用宽字符串文字。好的。性病:咳嗽

    使用<<输出到控制台时,只能使用std::string,不能使用std::wstring,文本必须使用区域设置代码页编码。如果您有一个std::wstring,那么您必须使用一个Windows API函数转换它,并且代码页上没有的任何字符都将被?替换(也许您可以更改字符,我不记得了)。好的。std::fstream文件名

    Windows操作系统使用ucs2/utf-16作为文件名,因此无论您的代码页是什么,您都可以使用任何Unicode字符的文件。但这意味着要访问或创建不在代码页上的字符文件,必须使用std::wstring。没有别的办法。这是微软对std::fstream的特定扩展,因此可能不会在其他系统上编译。如果使用std::string,则只能使用仅包含代码页上字符的文件名。好的。你的选择

    如果您只是在Linux上工作,那么您可能还没有达到这个目标。只要在任何地方使用UTF-8 std::string。好的。

    如果您只是在Windows上工作,请在任何地方使用ucs2 std::wstring。一些纯粹主义者可能会说,在需要的时候使用utf8然后转换,但是为什么要麻烦呢?好的。

    如果你是跨平台的,那么坦白说就是一团糟。如果您试图在Windows上的任何地方使用UTF-8,那么您需要非常小心地处理字符串文本并将其输出到控制台。你可以很容易地破坏你的字符串。如果您在Linux上到处使用std::wstring,那么您可能无法访问std::fstream的广泛版本,因此您必须进行转换,但不存在损坏的风险。所以我个人认为这是一个更好的选择。很多人会不同意,但我不是唯一一个人——例如,这是wxwidgets所采取的路径。好的。

    另一种选择是在Linux上将unicodestring类型化为std::string,在Windows上将std::wstring,并有一个名为uni()的宏,该宏在Windows上前缀为l,在Linux上不加前缀,然后代码好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #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编写一些代码来解决这些差异,如果只是使用Linux,那么永远不会。好的。

    2)是的。此外,在Linux上,您也可以将其用于所有Unicode。在Windows上,如果选择使用UTF-8手动编码,则只能将其用于所有Unicode。但是Windows API和标准C++类将期望使用本地代码页编码EDOCX1 1。这包括所有的ASCII加上另外128个字符,这些字符根据您的计算机设置要使用的代码页而改变。好的。

    3)我相信是这样,但如果不是这样的话,它只是使用wchar_t而不是char的"std::basic_string"的简单typedef。好的。

    4)宽字符是大于1字节标准char类型的字符类型。在Windows上是2字节,在Linux上是4字节。好的。好啊。


    一个好问题!我认为数据编码(有时也涉及字符集)是一种内存表达式机制,用于将数据保存到文件或通过网络传输数据,因此我的回答如下:

    1。什么时候应该在std::string上使用std::wstring?

    如果编程平台或API函数是单字节的,并且我们想要处理或解析一些Unicode数据,例如从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八位字节代表一个字符,包括可打印文本,如"123abc&;*uuamp;",而您所说的特殊字符,大多是作为"."打印的,避免混淆编辑器或终端。另外一些国家扩展自己的"ascii"字符集,例如中文,使用2个八位字节代表一个字符。

    3、STD::WSCOPE是由所有流行的C++编译器支持的吗?

    也许,或者大部分。我用过:VC++6和GCC 3.3,是的。

    4。什么才是"宽性格"?

    宽字符主要表示使用2个八位字节或4个八位字节来保存所有国家的字符。2个八位字节ucs2是一个代表性样本,而且,例如英语"a",它的内存是2个八位字节0x0061(而在ascii"a"中,它的内存是1个八位字节0x61)


    上述模式1)As is for Greg,帮助wstring国际化,那当你释放你的产品会比在其他语言的英语P></

    4)看看这个为宽字符http:/ / / /字宽_维基百科en.wikipedia.orgP></


    当你使用should not characters宽?P></

    当你写作在1990年的队列。P></

    明显的,我被翻转,但这是真的,现在的第二十一世纪。自从ceased 127 characters have to be足够长。是的,你可以使用,但与headaches为什么打扰?P></