std :: wstring VS std :: string
我无法理解std::string
和std::wstring
之间的区别。 我知道wstring
支持宽字符,如Unicode字符。 我有以下问题:
- 什么时候应该使用
std::wstring
std::string
? -
std::string
保存整个ASCII字符集,包括特殊字符吗? - 所有stream行的C ++编译器都支持
std::wstring
吗? - 什么是“ 宽字符 ”?
string
? wstring
?
std::string
是在char
上basic_string
,在wchar_t
上是std::wstring
。
char
与wchar_t
char
应该保存一个字符,通常是一个1字节的字符。 wchar_t
应该是一个宽字符,然后,事情变得棘手:在Linux上, wchar_t
是4字节,而在Windows上,它是2-bytes
那么Unicode呢呢?
问题是char
和wchar_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_t
string,因此,即使历史应用程序使用像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的数字)。 但:
- ASCII应该从0到127.更高的字符不是ASCII。
- 从0到127的字符将被正确保存
- 从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挫折和相应的经验如下:
-
接受,你必须自己负责的编码和转换的东西(你会看到它的大部分是相当微不足道的)
-
对任何UTF-8编码的string使用std :: string(只是一个
typedef std::string UTF8String
) -
接受这样一个UTF8String对象只是一个愚蠢的,但便宜的容器。 永远不要直接访问和/或操作字符(不search,replace等)。 你可以,但你真的只是真的,真的不想浪费你的时间编写多字节string的文本操作algorithm! 即使其他人已经做了这样的愚蠢的事情,不要这样做! 随它去! (好吧,有些情况下是有道理的,只是使用ICU库)。
-
使用std :: wstring为UCS-2编码的string(
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。 只要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调用附近执行转换。 文章中概述的好处超过转换的明显的烦恼,特别是在复杂的应用程序。 对于多平台和图书馆开发来说,这是双重的。
现在,回答你的问题:
- 有几个薄弱的原因。 它的存在是由于历史的原因,宽广的人被认为是支持Unicode的正确方式。 它现在被用来连接喜欢UTF-16string的API。 我只在这种API调用的附近使用它们。
- 这与std :: string没有任何关系。 它可以容纳你input的任何编码。 唯一的问题是你如何对待它的内容。 我的build议是UTF-8,所以它将能够正确保存所有的Unicode字符。 这在Linux上是很常见的做法,但我认为Windows程序也应该这样做。
- 没有。
- 宽字符是一个令人困惑的名字。 在Unicode的早期,有一种观点认为,字符可以用两个字节编码,因此名字就可以了。 今天,它代表“字符长度为两个字节的任何部分”。 UTF-16被看作是这种字节对(又名宽字符)的序列。 UTF-16中的字符需要一个或两个pares。
-
当你想要在你的string中存储宽字符。
wide
取决于实施。 Visual C ++默认为16位,如果我没有记错的话,而GCC的默认值取决于目标。 这里有32位长。 请注意wchar_t(宽字符types)与unicode无关。 它只能保证它可以存储实现所支持的最大字符集的所有成员,并且至less和char一样长。 你也可以使用UTFutf-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元素和逻辑字符。 - 是的,char总是至less有8位长,这意味着它可以存储所有的ASCII值。
- 是的,所有主要的编译器都支持它。
我经常使用std :: string来保存utf-8字符,没有任何问题。 我衷心推荐在与使用utf-8作为本机stringtypes的API接口时进行此操作。
例如,我在使用Tcl解释器连接我的代码时使用了utf-8。
主要的警告是std :: string的长度,不再是string中的字符数。
- 当你想存储“宽”(Unicode)字符。
- 是:255个(不包括0)。
- 是。
- 以下是一篇介绍性文章: http : //www.joelonsoftware.com/articles/Unicode.html
不满足于256个不同字符的应用程序可以使用宽字符(多于8位)或可变长度编码(C ++术语中的多字节编码)(如UTF-8)。 宽字符通常需要比可变长度编码更多的空间,但处理速度更快。 处理大量文本的多语言应用程序在处理文本时通常使用宽字符,但在将其存储到磁盘时将其转换为UTF-8。
string
和wstring
之间的唯一区别是它们存储的字符的数据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对于国际化是有帮助的,那就是当你用英文以外的语言发布你的产品的时候
- 当你想使用Unicodestring,而不仅仅是ascii,有助于国际化
- 是的,但是它不能很好地与0相配
- 不知道有没有
- 宽字符是编译器处理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,但为什么要头疼?