微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

恢复通过网络发送的结构

如何解决恢复通过网络发送的结构

我的同事想通过网络发送一些由类型 T 表示的数据。他通过将 T 强制转换为 char* 并使用带有套接字的 write(2) 调用发送它来做到这一点:

auto send_some_t(int sock,T const* p) -> void
{
    auto buffer = reinterpret_cast<char const*>(p);
    write(sock,buffer,sizeof(T));
}

到目前为止,一切都很好。这个简化的例子,除了去掉了任何错误检查之外,应该是正确的。假设类型 T 是可简单复制的,我们可以使用 std::mempcy() 在对象之间复制这种类型的值(根据 C++17 标准 [1] 中的 6.7 [basic.types] 点 3)所以我猜write(2) 也应该可以正常工作,因为它会盲目复制二进制数据。

棘手的地方在于接收方。

假设有问题的类型 T 如下所示:

struct T {
    uint64_t foo;
    uint8_t bar;
    uint16_t baz;
};

它有一个字段的对齐要求为 8 字节 (foo),因此整个类型需要 8 字节的严格对齐(参见 6.6.5 [basic.align] 点 2 的示例)。这意味着 T 类型的值的存储必须仅分配在合适的地址上。

现在,下面的代码怎么样?

auto receive_some_t(int sock,T* p) -> void
{
    read(sock,p,sizeof(T));
}

// ...

T value;
receive_some_t(sock,&T);

看起来很阴暗,但应该可以正常工作。接收到的字节do表示类型为 T 的有效值,并被盲目复制到类型为 T 的有效对象中。

但是,在以下代码中使用原始 char 缓冲区会怎样:

char buffer[sizeof(T)];
read_some_t(sock,buffer);

T* value = reinterpret_cast<T*>(buffer);

这是我的编码器大脑触发红色警报的地方。我们绝对不能保证 char[sizeof(T)] 的对齐与 T 的对齐,这是一个问题。我们也不返回指向有效 T 对象的指针,因为在我们的内存中没有类型为 T 的有效对象。而且我们不知道另一端使用了哪些编译器和选项(也许另一端的结构被打包而我们的不是)。

简而言之,我看到了将原始 char 缓冲区转换为其他类型的一些潜在问题,并会尽量避免编写上述代码。但显然它有效并且“每个人都这样做”。

我的问题是:根据 C++17 标准,恢复通过网络发送并接收到适当大小的 char 缓冲区的结构是否合法?

如果没有,使用 std::aligned_storage<sizeof(T),alignof(T)> 接收这样的结构怎么样?如果 std::aligned_storage 也不合法,是否有任何合法方式通过网络发送 raw 结构,或者这是一个碰巧有效的坏主意...直到它没有?

我将结构视为表示数​​据类型的一种方式,并将编译器在内存中布置它们的方式视为实现细节,而不是作为可依赖的数据交换的有线格式,但我很容易出错。

[1] www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf

解决方法

危险的部分不是内存对齐,而是 T 对象的生命周期。当您将 reinterpret_cast<> 内存用作 T 指针时,不会创建对象的实例,并且使用它会导致 Undefined B 行为。

在 C++ 中,所有对象都必须产生和停止存在,从而定义它们的生命周期。这甚至适用于 intfloat 等基本数据类型。唯一的例外是 char

换句话说,合法的是将缓冲区中的字节复制到一个已经存在的对象中,如下所示:

char buffer[sizeof(T)];

// fill the buffer...

T value;
std::memcpy(&value,buffer,sizeof(T));

不要担心性能。编译器会优化所有这些。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?