使用C++11读写/打印UTF-8

9
我一直在探索C++11的新Unicode功能,虽然其他C++11编码问题非常有帮助,但我对cppreference中以下代码片段有疑问。该代码将一个使用UTF-8编码保存的文本文件写入并立即读取。
// Write
std::ofstream("text.txt") << u8"z\u6c34\U0001d10b";

// Read
std::wifstream file1("text.txt");
file1.imbue(std::locale("en_US.UTF8"));
std::cout << "Normal read from file (using default UTF-8/UTF-32 codecvt)\n";
for(wchar_t c; file1 >> c; ) // ?
   std::cout << std::hex << std::showbase << c << '\n';

我的问题很简单,为什么在for循环中需要wchar_t?可以使用简单的char *声明u8字符串字面值,并且UTF-8编码的位布局应该告诉系统字符的宽度。似乎存在从UTF-8自动转换为UTF-32(因此需要wchar_t),但如果是这种情况,为什么需要转换?

这取决于很多因素。特别是,在Windows控制台应用程序中正确使用UTF8行为非常困难,如果不是不可能的话(需要至少一些非标准API调用,如我所知)。 - sehe
1
使用wchar_t是因为使用了wifstream,而wifstream执行了你提到的“某些自动转换”。我的观点是要展示这种自动转换(在一个特定平台上实现)与codecvt_utf8_utf16提供的显式、可移植、与语言环境无关的Unicode转换之间的区别。 - Cubbi
2个回答

5
你使用是因为你使用读取文件;如果你使用读取,将使用,对于和同理。
假设(如示例所述),是32位的,并且它所表示的本机字符集是UTF-32(UCS-4),那么这是以UTF-32方式读取文件的最简单方法,在示例中呈现为与以UTF-16读取文件相对比。更具可移植性的方法是显式使用>和>,因为这保证了从UTF-8输入流转换为UTF-32元素。

1
+1,我写了那个例子,对比效果是我想要的。 - Cubbi
啊,我明白了!那么,将UTF-8显式转换为更宽的wchar_t是否总是更好的做法,还是仍然可以使用ifstream将原始的UTF-8字节提取到本地的char数组中?我不确定是否应该从@Cubbi的示例中推断出后者是不良实践,还是它只是超出了示例的范围。 - Ephemera
@PLPiper 是的,您可以始终将文件中的任何多字节编码读入 char 数组,而不涉及任何转换。在标准 C++ 中,这种数组除了首先转换为宽字符外,没有太多可以做的事情,但是有很多库可以接受 utf8 输入。 - Cubbi

2

cppreference代码片段的思路是展示如何将UTF-8文件读入一个UTF-16字符串,这就是为什么他们使用ofstream写文件,但使用wifstream读取它(因此使用wchar_t)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接