我无法理解 std::string
和 std::wstring
之间的区别。我知道 wstring
支持Unicode字符等宽字符。我有以下问题:
- 我什么时候应该使用
std::wstring
而不是std::string
? std::string
可以保存整个 ASCII 字符集,包括特殊字符吗?- 所有流行的 C++ 编译器都支持
std::wstring
吗? - 究竟什么是“ _宽字符_”?
原文由 Appu 发布,翻译遵循 CC BY-SA 4.0 许可协议
我无法理解 std::string
和 std::wstring
之间的区别。我知道 wstring
支持Unicode字符等宽字符。我有以下问题:
std::wstring
而不是 std::string
?std::string
可以保存整个 ASCII 字符集,包括特殊字符吗?std::wstring
吗?原文由 Appu 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
这里有一些非常好的答案,但我认为我可以添加一些关于 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 不一样,但出于我的目的,它们足够接近可以互换,我在这里使用它们。我实际上不确定使用哪个 Windows,但我通常也不需要知道。我已经在这个答案中声明了 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
中,但是您可能还没有使用宽字符串文字。标准::cout
当使用
<<
输出到控制台时,您只能使用std::string
,而不是std::wstring
并且必须使用您的语言环境代码页对文本进行编码。如果您有std::wstring
那么您必须使用 Windows API 函数之一进行转换,并且代码页上没有的任何字符都将替换为?
(也许您可以更改字符,我可以不记得了)。std::fstream 文件名
Windows 操作系统使用 UCS2/UTF-16 作为其文件名,因此无论您的代码页如何,您都可以拥有任何 Unicode 字符的文件。但这意味着要访问或创建包含不在您的代码页上的字符的文件,您必须使用
std::wstring
。没有其他办法。这是std::fstream
的 Microsoft 特定扩展,因此可能无法在其他系统上编译。如果您使用 std::string 那么您只能使用在您的代码页上仅包含字符的文件名。您的选择
如果您只是在 Linux 上工作,那么您可能还没有走到这一步。只需在任何地方使用 UTF-8
std::string
。如果您只是在 Windows 上工作,只需在任何地方使用 UCS2
std::wstring
。一些纯粹主义者可能会说使用 UTF8,然后在需要时进行转换,但为什么还要麻烦。如果您是跨平台的,那么坦率地说,这是一团糟。如果您尝试在 Windows 上的任何地方使用 UTF-8,那么您需要非常小心您的字符串文字并输出到控制台。您可以在那里轻松损坏您的字符串。如果您在 Linux 上的任何地方都使用
std::wstring
那么您可能无法访问广泛版本的std::fstream
,因此您必须进行转换,但没有损坏的风险。所以我个人认为这是一个更好的选择。许多人会不同意,但我并不孤单 - 例如 wxWidgets 采用的路径。另一种选择可能是在 Linux 上键入def
unicodestring
asstd::string
和std::wstring
在 Windows 上,并且在 Windows 上没有名为 UNI() 的宏,在 Windows 上没有前缀 L Linux,然后是代码我认为在任何一个平台上都可以。
答案
所以回答你的问题
1)如果您正在为 Windows 编程,那么一直,如果跨平台,那么可能一直,除非您想处理 Windows 上可能的损坏问题或编写一些特定于平台的代码
#ifdefs
工作围绕差异,如果只是使用Linux,那么永远不会。2)是的。此外,在 Linux 上,您也可以将它用于所有 Unicode。在 Windows 上,如果您选择使用 UTF-8 手动编码,则只能将其用于所有 unicode。但是 Windows API 和标准 C++ 类将期望
std::string
使用语言环境代码页进行编码。这包括所有 ASCII 加上另外 128 个字符,这些字符会根据您的计算机设置使用的代码页而变化。3)我相信是这样,但如果不是,那么它只是使用
wchar_t
而不是char
的简单 typedef ‘std::basic_string’4)宽字符是大于1字节标准的字符类型
char
类型。在 Windows 上是 2 个字节,在 Linux 上是 4 个字节。