首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::wstring VS std::string

std::wstring VS std::string
EN

Stack Overflow用户
提问于 2008-12-31 04:08:14
回答 13查看 388.9K关注 0票数 873

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

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

回答 13

Stack Overflow用户

发布于 2008-12-31 12:47:29

stringwstring

std::stringchar上的basic_string模板,std::wstringwchar_t上的模板。

charwchar_t

char应该保存一个字符,通常是8位字符.wchar_t应该有一个宽字符,然后,事情变得棘手起来:在Linux上,wchar_t是4字节,而在wchar_t上是2字节。

那么Unicode呢?

问题是,charwchar_t都没有直接绑定到unicode。

在Linux上?

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

代码语言:javascript
复制
#include <cstring>
#include <iostream>

int main()
{
    const char text[] = "olé";


    std::cout << "sizeof(char)    : " << sizeof(char) << "\n";
    std::cout << "text            : " << text << "\n";
    std::cout << "sizeof(text)    : " << sizeof(text) << "\n";
    std::cout << "strlen(text)    : " << strlen(text) << "\n";

    std::cout << "text(ordinals)  :";

    for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
    {
        unsigned char c = static_cast<unsigned_char>(text[i]);
        std::cout << " " << static_cast<unsigned int>(c);
    }

    std::cout << "\n\n";

    // - - -

    const wchar_t wtext[] = L"olé" ;

    std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << "\n";
    //std::cout << "wtext           : " << wtext << "\n"; <- error
    std::cout << "wtext           : UNABLE TO CONVERT NATIVELY." << "\n";
    std::wcout << L"wtext           : " << wtext << "\n";

    std::cout << "sizeof(wtext)   : " << sizeof(wtext) << "\n";
    std::cout << "wcslen(wtext)   : " << wcslen(wtext) << "\n";

    std::cout << "wtext(ordinals) :";

    for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
    {
        unsigned short wc = static_cast<unsigned short>(wtext[i]);
        std::cout << " " << static_cast<unsigned int>(wc);
    }

    std::cout << "\n\n";
}

输出以下案文:

代码语言:javascript
复制
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 (不包括尾随0)。(作为练习,我将让您学习wchar_t代码)

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

请注意,与C string一样,std::string将考虑"olé“字符串包含4个字符,而不是3个字符。因此,您在截断/使用unicode字符时应该谨慎,因为在UTF-8中禁止某些字符的组合。

在Windows上?

在Windows上,这有点不同。在Unicode出现之前,Win32必须支持许多使用char和在世界各地生产的不同字符集/代码页上工作的应用程序。

因此,他们的解决方案是一个有趣的解决方案:如果应用程序使用char工作,那么字符字符串就会被编码/打印/显示在GUI标签上,使用机器上的本地字符集/代码页,这在很长一段时间内不可能是UTF-8。例如,在法语本地化的Windows中,"olé“应该是"olé”,但是在西里尔语的本地化窗口上(如果使用Windows-1251,则是“olй”)。因此,“历史应用程序”通常仍将以同样的方式工作。

对于基于Unicode的应用程序,Windows使用2字节宽的wchar_t,并以乌特夫-16编码,后者是用2字节字符编码的(或者至少是UCS-2,它只是缺少代理对,因此没有BMP之外的字符(>= 64K))。

使用char的应用程序被称为“多字节”(因为每个字形由一个或多个char组成),而使用wchar_t的应用程序被称为"widechar“(因为每个字形由一个或两个wchar_t组成)。有关更多信息,请参见MultiByteToWideCharWideCharToMultiByte Win32转换API。

因此,如果您在Windows上工作,非常希望使用wchar_t (除非您使用一个框架来隐藏它,比如GTKQT )。事实上,Windows在幕后使用wchar_t字符串,因此即使是历史应用程序在使用API (如SetWindowText() (低级API函数)在Win32 GUI上设置标签时,也会在wchar_t中转换它们的SetWindowText()字符串)。

记忆问题?

UTF-32是每个字符4个字节,所以没有什么可添加的,如果一个UTF-8文本和UTF-16文本使用的内存总是比UTF-32文本少或相同的话(通常更少)。

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

然而,对于其他语言(中文、日语等),所使用的内存要么相同,要么比UTF-16略大一些。

总之,UTF-16通常每个字符使用2字节,有时使用4个字节(除非你在处理某种深奥的语言符号(克林贡?),而UTF-8将花费1到4个字节.

有关更多信息,请参见乌特夫-16

结论

  1. 当我应该使用std::wstring over std::时 在Linux上?几乎从不(§)。在Windows上?几乎总是(§)。跨平台代码?取决于你的工具箱..。 (§):除非您使用工具包/框架,否则不使用
  2. std::string 能容纳所有包含特殊字符的字符集吗? 注意:std::string适用于保存“二进制”缓冲区,而std::wstring不是! 在Linux上?是。在Windows上?仅适用于Windows用户当前区域设置的特殊字符。 编辑(在 std::string的注释之后,std::string将足以处理所有char-based字符串(每个char都是从0到255之间的数字)。但是:
代码语言:javascript
复制
1. ASCII is supposed to go from 0 to 127. Higher `char`s are NOT ASCII.
2. a `char` from 0 to 127 will be held correctly
3. a `char` from 128 to 255 will have a signification depending on your encoding (unicode, non-unicode, etc.), but it will be able to hold all Unicode glyphs as long as they are encoded in UTF-8.
  1. 几乎所有流行的std::wstring编译器都支持??? 大多数情况下,除了GCC的编译器被移植到Windows之外。它在我的g++ 4.3.2上工作(在Linux下),并且我在Win32上使用了Unicode,自从C++ 6之后。
  2. ,什么是宽字符? 在C/C++上,它是一个字符类型写的wchar_t,比简单的char字符类型要大。它应该用于将索引(如Unicode符号)大于255 (或127,取决于.)的字符放入其中。
票数 1.1K
EN

Stack Overflow用户

发布于 2009-12-29 16:14:55

我建议避免在Windows或其他地方使用std::wstring,除非在接口需要时,或者在Windows调用附近的任何地方,并将各自的编码转换作为语法糖。

我的观点被总结在http://utf8everywhere.org中,我是其中的一位作者.

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

现在,回答你们的问题:

  1. 一些微弱的原因。它的存在是出于历史原因,人们认为寡妇是支持Unicode的适当方式。现在,它被用于接口喜欢UTF-16字符串的API。我只在这种API调用的直接附近使用它们。
  2. 这与std::string无关。它可以保存你在里面放的任何密码。唯一的问题是You如何对待其内容。我的建议是UTF-8,所以它将能够正确地保存所有Unicode字符.这是Linux上的一种常见做法,但我认为Windows程序也应该这样做。
  3. 不是的。
  4. 宽字是个令人费解的名字。在Unicode的早期,人们相信一个字符可以用两个字节进行编码,因此可以使用名称。今天,它代表“字符的任何部分,即两个字节长”。UTF-16被看作是这样的字节对序列(也称为宽字符)。UTF-16中的一个字符可以是一对还是两对。
票数 102
EN

Stack Overflow用户

发布于 2011-11-07 06:07:09

所以,现在在座的每一位读者都应该对事实、情况有一个清晰的了解。如果不是,那么您必须阅读paercebal的非常全面的回答顺便说:谢谢!

我的实用主义结论非常简单:所有的C++ (和STL)“字符编码”的东西基本上都是坏的和无用的。把责任推到微软身上,反正也于事无补。

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

  1. 接受吧,你必须自己负责编码和转换(你会发现其中的大部分都是微不足道的)。
  2. 使用std::string用于任何UTF-8编码的字符串(只是一个typedef std::string UTF8String)
  3. 接受这样一个UTF8String对象只是一个愚蠢的,但廉价的容器。永远不要直接访问和/或操作其中的字符(没有搜索、替换等)。你可以,但你真的真的,真的不想浪费你的时间为多字节字符串编写文本操作算法!即使其他人已经做了如此愚蠢的事情,也不要那样做!甭管他们!(嗯,在某些情况下,这是合理的.只需使用ICU库)。
  4. 使用std::wstring用于UCS-2编码字符串(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-8I/O,在必须解析和/或操作字符串的地方使用UCS2String。您可以随时在这两种表示之间进行转换。

替代品和改进

  • 从和到单字节字符编码(例如,ISO8859-1)的转换可以通过平移表(例如const wchar_t tt_iso88951[256] = {0,1,2,...}; )和适当的代码转换到和从UCS2来实现。
  • 如果UCS-2不够,请切换到UCS-4 (typedef std::basic_string<uint32_t> UCS2String)。

ICU或其他unicode库?

先进的东西。

票数 40
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/402283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档