std :: wstring VS std :: string
我无法理解std::string
和std::wstring
之间的区别。 我知道wstring
支持宽字符,如Unicode字符。 我有以下问题:
std::wstring
不是std::string
? std::string
保存整个ASCII字符集,包括特殊字符吗? 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个字节
那么Unicode呢呢?
问题是char
和wchar_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的数字)。 但:
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调用附近执行转换。 文章中概述的好处胜过转换的明显烦恼,特别是在复杂的应用程序中。 对于多平台和图书馆开发来说这是双重的。
现在,回答你的问题:
所以,这里的每个读者现在都应该清楚地了解事实和情况。 如果没有,那么你必须阅读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