std :: wstring VS std :: string

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

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

stringwstring

std::string是在charbasic_string ,在wchar_t上是std::wstring

charwchar_t

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

那么Unicode呢呢?

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

在Linux上?

我们来看一下Linux操作系统:我的Ubuntu系统已经可以识别unicode了。 当我使用charstring时,它以UTF-8 (即string的Unicodestring)本地编码。 以下代码:

 #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工作与字符,所以std ::string已经unicode就绪。

请注意,std :: string与CstringAPI一样,会认为“olé”string有4个字符,而不是3个字符。 所以你应该谨慎截断/播放Unicode字符,因为在UTF-8禁止一些字符组合。

在Windows上?

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

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

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

使用char应用程序被称为“多字节”(因为每个字形都由一个或多个char组成),而使用wchar_t应用程序被称为“widechar”(因为每个字形都由一个或两个wchar_t 。获取更多信息。

因此,如果你在Windows上工作,你很想使用wchar_t (除非你使用隐藏GTK +或QT的框架)。 事实上,在幕后,Windows使用wchar_tstring,因此,即使历史应用程序使用像SetWindowText(低级API函数在Win32 GUI上设置标签)的API时,也会将其string转换为wchar_t

内存问题?

UTF-32是每个字符4个字节,所以没有太多的添加,如果只有一个UTF-8文本和UTF-16文本将总是使用比UTF-32文本更less或相同数量的内存(通常更less)。

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

对于其他语言(中文,日文等),所使用的内存将相同,或者对于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适合于保存一个“二进制”缓冲区,其中一个std :: wstring不是!

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

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

  1. ASCII应该从0到127.更高的字符不是ASCII。
  2. 从0到127的字符将被正确保存
  3. 从128到255的字符将取决于你的编码(unicode,non-unicode等),但是只要它们以UTF-8编码,它就能够保存所有的Unicode字形。

3.几乎所有stream行的C ++编译器都支持std :: wstring吗?

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

4.什么是宽字符?

在C / C ++上,它是一个字符types,写成wchar_t ,它比简单的字符types大。 它应该被用来放入字符的索引(如Unicode字形)大于255(或127,取决于…)

所以,这里的每个读者都应该对事实和情况有一个清醒的认识。 如果没有,那么你必须阅读paercebal杰出的全面的答案 [顺便说一句:谢谢!

我的实用结论非常简单:所有C ++(和STL)“字符编码”的东西实质上已经被破坏和无用。 指责它在微软或不,无论如何不会有帮助。

经过深入调查,我的解决办法是多less挫折和相应的经验如下:

  1. 接受,你必须自己负责的编码和转换的东西(你会看到它的大部分是相当微不足道的)

  2. 对任何UTF-8编码的string使用std :: string(只是一个typedef std::string UTF8String

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

  4. 使用std :: wstring为UCS-2编码的string( 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 ); 

转换是直接的,谷歌应该帮助这里…

而已。 使用UTF8String无论内存是珍贵的还是所有UTF-8 I / O。 只要string必须被parsing和/或操纵,就使用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库?

先进的东西。

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

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

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

现在,回答你的问题:

  1. 有几个薄弱的原因。 它的存在是由于历史的原因,宽广的人被认为是支持Unicode的正确方式。 它现在被用来连接喜欢UTF-16string的API。 我只在这种API调用的附近使用它们。
  2. 这与std :: string没有任何关系。 它可以容纳你input的任何编码。 唯一的问题是如何对待它的内容。 我的build议是UTF-8,所以它将能够正确保存所有的Unicode字符。 这在Linux上是很常见的做法,但我认为Windows程序也应该这样做。
  3. 没有。
  4. 宽字符是一个令人困惑的名字。 在Unicode的早期,有一种观点认为,字符可以用两个字节编码,因此名字就可以了。 今天,它代表“字符长度为两个字节的任何部分”。 UTF-16被看作是这种字节对(又名宽字符)的序列。 UTF-16中的字符需要一个或两个pares。
  1. 当你想要在你的string中存储宽字符。 wide取决于实施。 Visual C ++默认为16位,如果我没有记错的话,而GCC的默认值取决于目标。 这里有32位长。 请注意wchar_t(宽字符types)与unicode无关。 它只能保证它可以存储实现所支持的最大字符集的所有成员,并且至less和char一样长。 你也可以使用UTF utf-8编码 unicodestring存储std::string 。 但它不会理解unicode代码点的含义。 所以str.size()不会给你的string中的逻辑字符数量,而只是存储在string/ wstring中的char或wchar_t元素的数量。 出于这个原因,gtk / glib C ++包装人员开发了一个可以处理utf-8的Glib::ustring类。

    如果你的wchar_t是32位长,那么你可以使用utf-32作为unicode编码,你可以使用固定的(utf-32是固定长度)编码来存储处理unicodestring。 这意味着你的wstring的s.size()函数将返回适量的wchar_t元素逻辑字符。

  2. 是的,char总是至less有8位长,这意味着它可以存储所有的ASCII值。
  3. 是的,所有主要的编译器都支持它。

我经常使用std :: string来保存utf-8字符,没有任何问题。 我衷心推荐在与使用utf-8作为本机stringtypes的API接口时进行此操作。

例如,我在使用Tcl解释器连接我的代码时使用了utf-8。

主要的警告是std :: string的长度,不再是string中的字符数。

  1. 当你想存储“宽”(Unicode)字符。
  2. 是:255个(不包括0)。
  3. 是。
  4. 以下是一篇介绍性文章: http : //www.joelonsoftware.com/articles/Unicode.html

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

stringwstring之间的唯一区别是它们存储的字符的数据types。 一个string存储的char的大小保证至less8位,所以你可以使用string进行处理,例如ASCII,ISO-8859-15或UTF-8文本。 该标准没有提到字符集或编码。

实际上,每个编译器都使用一个字符集,其前128个字符与ASCII对应。 使用UTF-8编码的编译器也是如此。 在UTF-8或其他可变长度编码中使用string时要注意的重要事项是,索引和长度是以字节而不是字符来度量的。

wstring的数据types是wchar_t ,它的大小在标准中没有定义,除了它必须至less和char一样大,通常是16位或32位。 可以使用wstring来处理实现定义的宽字符编码中的文本。 因为编码没有在标准中定义,所以在string和string之间转换并不简单。 人们不能假设wstrings也有一个固定长度的编码。

如果您不需要多语言支持,则只需使用常规string即可。 另一方面,如果您正在编写graphics应用程序,则API通常只支持宽字符。 那么你可能想在处理文本时使用相同的宽字符。 请记住,UTF-16是一种可变长度编码,这意味着您不能假定length()返回字符数。 如果API使用固定长度编码(例如UCS-2),则处理变得容易。 宽字符和UTF-8之间的转换很难以可移植的方式进行,但是再次,您的用户界面API可能支持转换。

1)正如Greg所说的,wstring对于国际化是有帮助的,那就是当你用英文以外的语言发布你的产品的时候

4)检查这个宽字符http://en.wikipedia.org/wiki/Wide_character

  1. 当你想使用Unicodestring,而不仅仅是ascii,有助于国际化
  2. 是的,但是它不能很好地与0相配
  3. 不知道有没有
  4. 宽字符是编译器处理unicode字符的固定长度表示的具体方式,对于MSVC它是2字节字符,对于gcc我知道它是4字节。 和+1的http://www.joelonsoftware.com/articles/Unicode.html

一个好问题! 我认为数据编码 (有时也涉及CHARSET )是一个内存expression机制,以便将数据保存到文件或通过networking传输数据,所以我回答这个问题为:

1.什么时候应该使用std :: wstring而不是std :: string?

如果编程平台或API函数是单字节的,我们要处理或parsing一些Unicode数据,例如从Windows的.REG文件或networking2字节stream中读取,我们应该声明std :: wstringvariables处理它们。 例如:wstring ws = L“中国a”(6个八位字节的内存:0x4E2D 0x56FD 0x0061),我们可以用ws [0]得到字符'中'和ws [1]得到字符'国'和ws [2]得到人物“a”等

2.可以std :: string保存整个ASCII字符集,包括特殊字符?

是。 但注意:美国的ASCII,意思是每个0x00〜0xFF的八位字节代表一个字符,包括可打印的文本,如“123abc&* _&”,你说的特别的,大多打印成“。 避免混淆编辑或terminal。 而其他一些国家则扩展自己的“ASCII”字符集,例如中文,用2个八位字节代表一个字符。

3.所有stream行的C ++编译器都支持std :: wstring吗?

也许,或大多数。 我用过:VC ++ 6和GCC 3.3,是的

4.什么是“宽字符”?

宽字符大多表示使用2个八位字节或4个八位字节来存放所有国家的字符。 2个八比特组UCS2是一个有代表性的样本,并且进一步例如英语“a”,其存储器是2个八位字节0x0061(vs在ASCII中,a的存储器是1个八位字节0x61)

什么时候不应该使用宽字符?

当你在1990年之前写代码的时候。

显然,我正在翻转,但现在是21世纪。 长期以来,127个字符已经不够用了。 是的,你可以使用UTF8,但为什么要头疼?