【问题标题】:UNIX sockets::recv, std::byte, and strict aliasingUNIX sockets::recv、std::byte 和严格别名
【发布时间】: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&lt;char&gt; 类型吗?我想这很好,但我不是 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_viewbuffer 吗? 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


【解决方案1】:

在这种情况下,charbyte 之间没有区别。事实上,最初这些网络功能是根据char 数据类型定义的。很久以前recv 的第二个参数是char *,而不是现在的void *

这将使std::vector&lt;char&gt; 转换为std::string 一个空的汉堡。你甚至可以选择完全放弃std::vector&lt;char&gt;。您可以预先调整std::string 的大小,然后直接将recv() 调整到其中,然后根据接收到的字节数再次调整大小。

【讨论】:

  • 这些类型之间存在差异,但有特定的别名规则允许这种情况。
猜你喜欢
  • 2018-12-14
  • 1970-01-01
  • 2023-02-02
  • 2012-05-20
  • 2021-07-04
  • 1970-01-01
  • 2019-02-09
  • 2017-10-23
  • 2012-11-08
相关资源
最近更新 更多