【发布时间】:2021-05-23 22:40:21
【问题描述】:
我正在编写一个基本上包装recv的函数:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
特别想写接收一些字节;有时这些字节将是 ASCII 字符串的一部分,有时它们将是整数,或者可能只是作为某些更高级别协议的一部分的普通“字节”。
我认为在现代 C++ 中抽象它的正确方法可能是写入std::byte 缓冲区,所以可能是这样的
std::vector<std::byte> buffer;
buffer.resize(100);
recv(socket, buffer.data(), 100, /* flags = */ 0);
我的第一个问题是:如上所述写入std::bytes 的“缓冲区”有什么问题吗?缓冲区应该是std::vector<char> 类型吗?我想这很好,但我不是 100% 确定。
我的第二个问题如下:假设现在我想将buffer 视为一个字符串。代码
std::string str(buffer.data(), 100);
失败是因为 std::byte* 没有转换为 const char*,我几乎可以肯定
std::string str(reinterpret_cast<const char*>(buffer.data()), 100);
由于严格的别名规则,是未定义的行为。
这是使用memcpy 之类的唯一方法:
std::string ret;
ret.resize(100);
std::memcpy(ret.data(), buffer.data(), 100);
?
如果我想要std::string_view 怎么办?我可以在不首先将字节实际复制到某个中间位置的情况下制作std::string_view 的buffer 吗? std::bit_cast 可以吗?
有趣的是,clang 并没有抱怨类似于std::string(reinterpret_cast... 解决方案的东西:https://godbolt.org/z/7zshhr(甚至使用-fsanitize=address 或-fsanitize=undefined 编译)
【问题讨论】:
-
请记住,
recv可以并且将返回比请求少的字节数。因此,在检查返回结果后准备调整缓冲区大小。或者使用 MSG_WAITALL 标志 - 但您仍然必须处理少于预期的字节数。
标签: c++ sockets c++20 strict-aliasing address-sanitizer