문제

다음 코드를 고려해보세요.

#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" 올바른 줄 끝 텍스트 파일 동작을 얻으려면

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top