首选Unicode来处理大字符集(例如emojis).
使用Unicode的首选方法是使用[`char16_t`和`char32_t`](http://en.cppreference.com/w/cpp/language/types#Character_types),因为它们具有已知的大小和范围.
2> o11c..:
切勿使用wchar_t
.
如果可能,使用(某种数组)char
,例如std::string
,并确保它以UTF-8编码.
如果必须与不使用UTF-8的API进行交互,请使用char16_t
或char32_t
.否则不要使用它们; 它们只提供虚幻的优势并鼓励错误的代码.
请注意,在很多情况下,需要多个char32_t
表示单个用户可见字符的情况.OTOH,使用UTF-8 char
强迫您尽早处理可变宽度.
某些Windows API需要`wchar_t`,但是在Windows上您知道`wchar_t`是16位并且具有一定的稳定性。而且char32_t可以表示所有Unicode字符,这可能只是用户认为的字符的一个子集,但有时却很有用。我同意`char16_t`可能仅在与需要UTF-16的系统接口时才有用。
3> StaceyGirl..:
简短的anwser:
wchar_t
除非与特定于操作系统的API交互(基本上wchar_t
只用于调用Windows API函数),否则永远不要在现代C++中使用.
答案很长:
标准C++库的设计意味着只有一种方法可以处理Unicode - 通过在char数组中存储UTF-8编码的字符串,因为几乎所有函数都只存在于char变体中(想想std::exception::what
).
在C++程序中,您有两种语言环境: - 标准C库语言环境设置std::setlocale
- 标准C++库语言环境设置std::locale::global
不幸的是,他们没有定义的打开文件(如标准功能的行为std::fopen
,std::fstream::open
等等).操作系统之间的行为不同: - Linux编码不可知,因此这些函数只是将char字符串传递给底层系统调用 - 在Windows系统调用之前,使用用户特定的语言环境将Windows字符串转换为宽字符串
一切都通常在Linux上正常工作,因为每个人都使用基于UTF-8的语言环境,因此传递给main
函数的所有用户输入和参数都将采用UTF-8编码.但是您可能仍需要显式地将当前语言环境切换为UTF-8变体,因为默认情况下C++程序使用默认"C"
语言环境启动.此时,如果您只关心Linux并且不需要支持Windows,则可以使用char数组并std::string
假设它是UTF-8序列并且所有内容都"正常".
当您想要支持Windows时出现问题,因为在这里您总是有另外的第三个区域设置:为当前用户设置的一个区域,可以在"控制面板"中的某处配置.主要问题是这个语言环境永远不是unicode语言环境,因此不可能使用类似函数std::fopen(const char *)
和std::fstream::open(const char *)
使用Unicode路径打开文件.在Windows上,你将不得不使用使用非标准的Windows的特定功能,如自定义的包装_wfopen
,std::fstream::open(const wchar_t *)
在Windows上.您可以查看Boost.Nowide(尚未包含在Boost中)以了解如何执行此操作:http://cppcms.com/files/nowide/html/
使用C++ 17,您可以使用std::filesystem::path
以便携方式存储文件路径,但它仍然在Windows上被破坏:
隐式构造函数std::filesystem::path::path(const char *)
在MSVC上使用特定于用户的区域设置,并且无法使其使用UTF-8.函数std::filesystem::u8string
应该用于从UTF-8字符串构造路径,但是很容易忘记这一点而是使用隐式构造.
std::error_category::message(int)
对于两个错误类别,使用特定于用户的编码返回错误描述.
所以我们在Windows上拥有的是:
打开文件的标准库函数已损坏,永远不应使用.
传递给的参数main(int, char**)
被破坏,永远不应该使用.
以*A和宏结尾的WinAPI函数被破坏,永远不应该使用.
std::filesystem::path
部分损坏,不应直接使用.
错误类型的返回std::generic_category
和std::system_category
破裂,绝不应该被使用.
如果你需要一个非平凡的项目的长期解决方案,我会建议:
使用Boost.Nowide或直接实现类似的功能 - 这个固定的破坏标准库.
重新实现返回的标准错误类别std::generic_category
,std::system_category
以便它们始终返回UTF-8编码的字符串.
包装,std::filesystem::path
以便在将路径转换为字符串并将字符串转换为路径时,新类始终使用UTF-8.
包装所有必需的函数,std::filesystem
以便它们使用您的路径包装器和您的错误类别.
不幸的是,这不会解决其他使用文件的库的问题,但是其中99%都会被破坏(不支持unicode).
这就是C++程序员的生活.Microsoft可以通过允许我们将Windows运行时切换到基于UTF-8的语言环境来解决这个问题,但由于向后兼容性,它们不会.
您可以查看此链接以获得进一步说明:http://utf8everywhere.org/