Visual C++의 유니코드 리터럴
-
26-12-2019 - |
문제
다음 코드를 고려해보세요.
#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(Ubuntu 14.04)의 GCC 4.8에서 파일은 test.txt
다음을 포함합니다:
6:€€
Windows의 Visual C++ 2013에는 다음이 포함되어 있습니다.
4:€\x80
('\x80'은 단일 8비트 문자 0x80을 의미합니다.)
나는 두 컴파일러 모두에서 다음을 출력하도록 할 수 없었습니다. €
캐릭터를 사용하는 std::wstring
.
두 가지 질문:
- Microsoft 컴파일러는 정확히 무엇을 하고 있다고 생각합니까?
char*
오자?분명히 인코딩하기 위해 뭔가를 하고 있지만 무엇이 명확하지 않습니다. - 다음을 사용하여 위 코드를 다시 작성하는 올바른 방법은 무엇입니까?
std::wstring
그리고std::wofstream
그래서 2개를 출력한다.€
캐릭터?
해결책
이것은 당신이 사용하고 있기 때문입니다 \u20ac
이는 ASCII 문자열의 유니코드 문자 리터럴입니다.
MSVC 인코딩 "\xe2\x82\xac\u20ac"
~처럼 0xe2, 0x82, 0xac, 0x80,
이는 4개의 좁은 문자입니다.본질적으로 인코딩합니다. \u20ac
유로 문자를 표준에 매핑했기 때문에 0x80으로 표시됩니다. 1252 코드페이지
GCC는 유니코드 리터럴을 변환하고 있습니다. /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개의 유니코드 문자가 표시됩니다.
다음 문제는 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"
올바른 줄 끝 텍스트 파일 동작을 얻으려면