std::cin.read() 读取流失败

std::cin.read() fails to read stream

我正在为浏览器扩展实现 native host。我围绕 std::cin 而不是 C 风格 getchar()

设计了我的实现

这里的问题是 std::cin 没有以二进制模式打开,这对基于 Windows 的主机有影响,因为 Chrome 浏览器不能很好地与 Windows 一起工作样式 \r\n 因此我必须以二进制模式阅读它。

要以二进制模式读取,我必须使用 _setmode(_fileno(stdin), _O_BINARY);

我的 IDE 找不到 _fileno 的定义,我发现解决方法是使用以下宏,

#if !defined(_fileno)
#define _fileno(__F) ((__F)->_file)
#endif

但是,我对这个宏没有足够的信心。我认为出了点问题,但我使用的是最新的 MinGW 编译器,不确定为什么没有定义它。

更新:这个功能似乎在 __STRICT_ANSI__ 后面,我不知道如何禁用它。

无论如何,程序编译正常,浏览器启动它,当我从浏览器发送消息时,应用程序能够读取消息的长度,当它尝试读取内容时,std::cin.read()操作不会向缓冲区向量插入任何内容,消息也不会以 null 终止,但我认为这不会导致问题。

我也尝试过在不阅读的情况下向浏览器发送一条虚拟消息,但它似乎冻结了浏览器。

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>

#ifdef __WIN32
#include <fcntl.h>
#include <io.h>
#endif

#if !defined(_fileno)
#define _fileno(__F) ((__F)->_file)
#endif

enum class Platforms {
    macOS = 1,
    Windows = 2,
    Linux = 3
};

Platforms platform;

#ifdef __APPLE__
    constexpr Platforms BuildOS = Platforms::macOS;
#elif __linux__
    constexpr Platforms BuildOS = Platforms::Linux;
#elif __WIN32
    constexpr Platforms BuildOS = Platforms::Windows;
#endif


void sendMessage(std::string message) {
    auto *data = message.data();
    auto size = uint32_t(message.size());

    std::cout.write(reinterpret_cast<char *>(&size), 4);
    std::cout.write(data, size);
    std::cout.flush();
}

int main() {
    if constexpr(BuildOS == Platforms::Windows) {
        // Chrome doesn't deal well with Windows style \r\n
        _setmode(_fileno(stdin), _O_BINARY);
        _setmode(_fileno(stdout), _O_BINARY);
    }

    while(true) {
        std::uint32_t messageLength;

        // First Four contains message legnth
        std::cin.read(reinterpret_cast<char*>(&messageLength), 4);

        if (std::cin.eof())
        {
            break;
        }

        std::vector<char> buffer;

        // Allocate ahead
        buffer.reserve(std::size_t(messageLength) + 1);

        std::cin.read(&buffer[0], messageLength);

        std::string message(buffer.data(), buffer.size());

        sendMessage("{type: 'Hello World'}");
    } 
}

解决方案:

buffer.reserve(std::size_t(messageLength) + 1);

应该是

buffer.resize(std::size_t(messageLength) + 1);

或者我们可以在构造过程中使用

预先调整缓冲区大小
std::vector<char> buffer(messageLength +1);

问题解释:

buffer.reserve(std::size_t(messageLength) + 1);

保留容量但不更改 vector 的大小,所以技术上

std::cin.read(&buffer[0], messageLength);`

是非法的,在

std::string message(buffer.data(), buffer.size());` 

buffer.size() 仍然是 0。