UNIX sockets::recv、std::byte 和严格别名
UNIX sockets::recv, std::byte, and strict aliasing
我正在写一个函数,基本上包装 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::byte
的“缓冲区”是否有任何问题?缓冲区应该是 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
怎么办?我可以制作 buffer
的 std::string_view
而无需先将字节实际复制到某个中间位置吗? std::bit_cast
可以吗?
有趣的是,clang 不会抱怨类似于 std::string(reinterpret_cast...
解决方案的问题:https://godbolt.org/z/7zshhr(甚至使用 -fsanitize=address
或 -fsanitize=undefined
编译)
在这种情况下,char
和 byte
之间没有区别。事实上,最初这些网络功能是根据 char
数据类型定义的。很久以前,recv
的第二个参数是 char *
,而不是现在的 void *
。
这将使 std::vector<char>
变成 std::string
一个空汉堡。您甚至可以选择完全放弃 std::vector<char>
。您可以预先调整 std::string
的大小,然后直接 recv()
调整大小,然后根据收到的字节数再次调整大小。
我正在写一个函数,基本上包装 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::byte
的“缓冲区”是否有任何问题?缓冲区应该是 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
怎么办?我可以制作 buffer
的 std::string_view
而无需先将字节实际复制到某个中间位置吗? std::bit_cast
可以吗?
有趣的是,clang 不会抱怨类似于 std::string(reinterpret_cast...
解决方案的问题:https://godbolt.org/z/7zshhr(甚至使用 -fsanitize=address
或 -fsanitize=undefined
编译)
在这种情况下,char
和 byte
之间没有区别。事实上,最初这些网络功能是根据 char
数据类型定义的。很久以前,recv
的第二个参数是 char *
,而不是现在的 void *
。
这将使 std::vector<char>
变成 std::string
一个空汉堡。您甚至可以选择完全放弃 std::vector<char>
。您可以预先调整 std::string
的大小,然后直接 recv()
调整大小,然后根据收到的字节数再次调整大小。