Visual C ++中的Unicode文字

时间:2014-08-01 03:02:12

标签: visual-c++ unicode unicode-escapes unicode-literals

请考虑以下代码:

#include <string>
#include <fstream>
#include <iomanip>

int main() {
    std::string s = "\xe2\x82\xac\u20ac";
    std::ofstream out("test.txt");
    out << s.length() << ":" << s << std::endl;
    out << std::endl;
    out.close();
}

在Linux上的GCC 4.8(Ubuntu 14.04)下,文件test.txt包含:

6:€€

在Windows上的Visual C ++ 2013下,它包含:

4:€\x80

(&#39; \ x80&#39;我指的是单个8位字符0x80)。

我完全无法让任何一个编译器使用输出std::wstring字符。

两个问题:

  • Microsoft编译器认为它对char*字面值的影响究竟是什么?它显然做了一些编码,但还不清楚。
  • 使用std::wstringstd::wofstream重写上述代码的正确方法是什么,以便输出两个字符?

1 个答案:

答案 0 :(得分:3)

这是因为您使用的是\u20ac,它是ASCII字符串中的Unicode字符文字。

MSVC将"\xe2\x82\xac\u20ac"编码为0xe2, 0x82, 0xac, 0x80,,这是4个窄字符。它基本上将\u20ac编码为0x80,因为它将欧元字符映射到标准1252 codepage

GCC正在将Unicode文字/u20ac转换为3字节的UTF-8序列0xe2, 0x82, 0xac,因此生成的字符串最终为0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac

如果您使用std::wstring = L"\xe2\x82\xac\u20ac",它会被MSVC编码为0xe2, 0x00, 0x82, 0x00, 0xac, 0x00, 0xac, 0x20,这是4个宽字符,但由于您将手工创建的UTF-8与UTF-16混合,因此生成的字符串不会没有多大意义。如果您使用std::wstring = L"\u20ac\u20ac",则可以按照您的预期在宽字符串中获得2个Unicode字符。

下一个问题是MSVC的ofstream和wofstream总是用ANSI / ASCII编写。要使其以UTF-8编写,您应该使用<codecvt>(VS 2010或更高版本):

#include <string>
#include <fstream>
#include <iomanip>
#include <codecvt>

int main()
{
    std::wstring s = L"\u20ac\u20ac";

    std::wofstream out("test.txt");
    std::locale loc(std::locale::classic(), new std::codecvt_utf8<wchar_t>);
    out.imbue(loc);

    out << s.length() << L":" << s << std::endl;
    out << std::endl;
    out.close();
}

并编写UTF-16(或更具体地说是UTF-16LE):

#include <string>
#include <fstream>
#include <iomanip>
#include <codecvt>

int main()
{
    std::wstring s = L"\u20ac\u20ac";

    std::wofstream out("test.txt", std::ios::binary );
    std::locale loc(std::locale::classic(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>);
    out.imbue(loc);

    out << s.length() << L":" << s << L"\r\n";
    out << L"\r\n";
    out.close();
}

注意:使用UTF-16时,您必须使用二进制模式而不是文本模式以避免损坏,因此我们无法使用std::endl并且必须使用L"\r\n"来获取正确的结尾 - 行文本文件行为。