Windows控制台上的UTF-8输出 下面的代码显示了我的机器上的意外行为(用Visual C++ 2008 SP1在Windows XP和Windows 7上的VS 2012进行测试): #包括 #包括“Windows.h” int main(){ 设置控制台输出CP(CP_UTF8); std::cout

Windows控制台上的UTF-8输出 下面的代码显示了我的机器上的意外行为(用Visual C++ 2008 SP1在Windows XP和Windows 7上的VS 2012进行测试): #包括 #包括“Windows.h” int main(){ 设置控制台输出CP(CP_UTF8); std::cout,c++,visual-studio-2008,utf-8,windows-xp,console,C++,Visual Studio 2008,Utf 8,Windows Xp,Console,Oi。恭喜你找到了一种从程序内部更改控制台代码页的方法。我不知道那个调用,我总是使用chcp 我猜测C++默认区域正在被加入。默认情况下,它将使用GETTHealLoad()提供的代码页来确定非WSCOPE的文本编码。这通常默认为CP1252。您可以尝试使用StTeReListalEL()来获得UTF-8(如果它甚至这样做,也不能回忆),希望std::locale默认为可以处理UTF-8编码的内容。现在是时候结束此操作了。Stephan T.Lavavej此行为是“设计的”,尽管我无法理解此解释

Oi。恭喜你找到了一种从程序内部更改控制台代码页的方法。我不知道那个调用,我总是使用chcp


我猜测C++默认区域正在被加入。默认情况下,它将使用GETTHealLoad()提供的代码页来确定非WSCOPE的文本编码。这通常默认为CP1252。您可以尝试使用StTeReListalEL()来获得UTF-8(如果它甚至这样做,也不能回忆),希望std::locale默认为可以处理UTF-8编码的内容。

现在是时候结束此操作了。Stephan T.Lavavej此行为是“设计的”,尽管我无法理解此解释

我目前的知识是:UTF-8代码页中的WindowsXP控制台不能与C++ IoStudio一起工作。 Windows XP现在已经不流行了,VS 2008也不流行了。我很想知道这个问题在较新的Windows系统上是否仍然存在


<> >强> Windows 7的输出>字符可能是由于C++流输出字符的方式。如在回答中所见,UTF-8输出在一次又一次打印后像C STDIO一样失败,如<代码> PTCC('\xC3);这可能是C++流在这里做的。

我理解这个问题很老,但是如果有人仍然感兴趣,下面是我的解决方案。我已经实现了一个非常简单的STD::StRIGBF子代,然后在程序执行的开始时将它传递给每个标准流。 这允许您在程序中的任何地方使用UTF-8。输入时,数据以Unicode格式从控制台获取,然后转换并以UTF-8格式返回给您。输出时则相反,以UTF-8格式从您获取数据,将其转换为Unicode格式并发送到控制台。目前为止,未发现任何问题

还请注意,此解决方案不需要任何代码页修改,包括
SetConsoleCP
SetConsoleOutputCP
chcp
或其他内容

这就是流缓冲区:

class ConsoleStreamBufWin32 : public std::streambuf
{
public:
    ConsoleStreamBufWin32(DWORD handleId, bool isInput);

protected:
    // std::basic_streambuf
    virtual std::streambuf* setbuf(char_type* s, std::streamsize n);
    virtual int sync();
    virtual int_type underflow();
    virtual int_type overflow(int_type c = traits_type::eof());

private:
    HANDLE const m_handle;
    bool const m_isInput;
    std::string m_buffer;
};

ConsoleStreamBufWin32::ConsoleStreamBufWin32(DWORD handleId, bool isInput) :
    m_handle(::GetStdHandle(handleId)),
    m_isInput(isInput),
    m_buffer()
{
    if (m_isInput)
    {
        setg(0, 0, 0);
    }
}

std::streambuf* ConsoleStreamBufWin32::setbuf(char_type* /*s*/, std::streamsize /*n*/)
{
    return 0;
}

int ConsoleStreamBufWin32::sync()
{
    if (m_isInput)
    {
        ::FlushConsoleInputBuffer(m_handle);
        setg(0, 0, 0);
    }
    else
    {
        if (m_buffer.empty())
        {
            return 0;
        }

        std::wstring const wideBuffer = utf8_to_wstring(m_buffer);
        DWORD writtenSize;
        ::WriteConsoleW(m_handle, wideBuffer.c_str(), wideBuffer.size(), &writtenSize, NULL);
    }

    m_buffer.clear();

    return 0;
}

ConsoleStreamBufWin32::int_type ConsoleStreamBufWin32::underflow()
{
    if (!m_isInput)
    {
        return traits_type::eof();
    }

    if (gptr() >= egptr())
    {
        wchar_t wideBuffer[128];
        DWORD readSize;
        if (!::ReadConsoleW(m_handle, wideBuffer, ARRAYSIZE(wideBuffer) - 1, &readSize, NULL))
        {
            return traits_type::eof();
        }

        wideBuffer[readSize] = L'\0';
        m_buffer = wstring_to_utf8(wideBuffer);

        setg(&m_buffer[0], &m_buffer[0], &m_buffer[0] + m_buffer.size());

        if (gptr() >= egptr())
        {
            return traits_type::eof();
        }
    }

    return sgetc();
}

ConsoleStreamBufWin32::int_type ConsoleStreamBufWin32::overflow(int_type c)
{
    if (m_isInput)
    {
        return traits_type::eof();
    }

    m_buffer += traits_type::to_char_type(c);
    return traits_type::not_eof(c);
}
其用法如下:

template<typename StreamT>
inline void FixStdStream(DWORD handleId, bool isInput, StreamT& stream)
{
    if (::GetFileType(::GetStdHandle(handleId)) == FILE_TYPE_CHAR)
    {
        stream.rdbuf(new ConsoleStreamBufWin32(handleId, isInput));
    }
}

// ...

int main()
{
    FixStdStream(STD_INPUT_HANDLE, true, std::cin);
    FixStdStream(STD_OUTPUT_HANDLE, false, std::cout);
    FixStdStream(STD_ERROR_HANDLE, false, std::cerr);

    // ...

    std::cout << "\xc3\xbc" << std::endl;

    // ...
}
模板
内嵌无效固定流(DWORD handleId、bool isInput、StreamT和stream)
{
如果(::GetFileType(::GetStdHandle(handleId))==文件类型\u字符)
{
stream.rdbuf(新控制台StreamBufwin32(handleId,isInput));
}
}
// ...
int main()
{
固定流(标准输入句柄,真,标准::cin);
FixStdStream(标准输出句柄,false,标准::cout);
FixStdStream(标准错误句柄,错误,标准::cerr);
// ...

STD::我以前遇到过C++ iOnSt流。有很多隐藏的缺点会导致问题。这是不值得的,但是当IoFieles给你带来麻烦时,使用C的STDIO,我以前已经多次遇到过这样的问题。是的,使用IoFielts比STDIO更复杂,甚至还有关于这一点。我很乐意使用它,给您带来了极大的灵活性。这不是Windows控制台的问题吗?我记得它无论如何都不支持unicode,造成了很多这样的问题……正如您所看到的,我可以在Windows控制台中输出UTF-8编码字符串(通过
fputs
)我可以用
type
命令键入UTF-8编码的文件(在完成
chcp 65001
之后)。因此我认为它可以处理这种编码…这肯定不是一个解决方案,但这是我以前从未想过的事情。我会在几天后回来工作时尝试(在家里我使用Linux…)。我又看了一遍,但SetThreadLocale没有处理编码,或者我不理解文档。我尝试了一点std::cout.imbue,但没有效果。这个问题仍然没有解决…这是一个有用的想法。对于输出,我最终得到了一个派生自
std::stringbuf
(因此我不必自己做缓冲)只需实现
sync()
进行转换。我的
sync()
将转换后的字符串插入到原始streambuf流中,而不是在代码中硬连接输出接收器。它存在:(我正试图在中找到一个解决方法,欢迎使用:)
template<typename StreamT>
inline void FixStdStream(DWORD handleId, bool isInput, StreamT& stream)
{
    if (::GetFileType(::GetStdHandle(handleId)) == FILE_TYPE_CHAR)
    {
        stream.rdbuf(new ConsoleStreamBufWin32(handleId, isInput));
    }
}

// ...

int main()
{
    FixStdStream(STD_INPUT_HANDLE, true, std::cin);
    FixStdStream(STD_OUTPUT_HANDLE, false, std::cout);
    FixStdStream(STD_ERROR_HANDLE, false, std::cerr);

    // ...

    std::cout << "\xc3\xbc" << std::endl;

    // ...
}