【问题标题】:How to map structure to char proper method in C++如何将结构映射到 C++ 中的正确方法
【发布时间】:2015-12-12 00:48:26
【问题描述】:

在 C 中,我习惯于使用 char*,我将一些表示网络数据包的结构映射到它。然后我只需分配数据包参数并通过网络发送:

已更新 - 我忘记补充说我有一些有效载荷

struct packet {
   uint64_t id __attribute__((packed)); 
   uint64_t something __attribute__((packed));
   short flags __attribute__((packed));
   // here follows payload with variable length
};
...
char *payload = get_payload();
size_t payload_size = get_payload_size();//doesnt matter how
char *data = malloc(sizeof(struct packet)+payload_size);
struct packet *pkt = (struct packet *)data;
pkt->id = 123;
pkt->something = get_something();
pkt->flags = FLAG | FLAG2;
memcpy(data+sizeof(struct packet), payload, payload_size);
send(data, sizeof(struct packet)+payload_size);

现在我想用一些不错的 C++ 特性来实现它(如果有任何可以更好地做到这一点的话) 我可以在 C++ 中做的最好的改变是使用 new 而不是 malloc。

char *data = new char[sizeof(struct packet)];//rest is same

好的,这称为对象序列化。我发现几个示例总是使用我无法使用的 boost。C++ 中没有本地方式来完成这个吗?

【问题讨论】:

  • 您所问的通常称为“对象序列化”。尝试使用谷歌搜索或搜索“C++ 对象序列化”的 SO。

标签: c++ networking struct


【解决方案1】:

没有理由创建char*pkt*。您创建并发送一个对象,例如:

packet pkt;  // create automatic object
pkt.id = 123;
pkt.something = get_something();
pktflags = FLAG | FLAG2;
// here we cast the address of pkt to a char* so we can send it
send(reinterpret_cast<char*>(&pkt), sizeof(packet));

编辑:

由于问题已更新为将有效负载添加到 struct 数据的末尾,您将不得不使用与 C 中相同的方法。当您将指针向上 new 时,语法将是

char * data = new char[sizeof(packet) + payload_size];

此外,在 C++ 中使用 struct 时,也不需要 struct 关键字,就像在 C 中一样。您可以按名称使用它。

【讨论】:

  • 谢谢,我喜欢你的解决方案,但我忘了补充说我在数据包之后使用了有效负载.. 抱歉更改问题。如果数据包将包含例如 char * 到有效负载,“reinterpret_cast 方式”会起作用吗?
【解决方案2】:

我不喜欢您的原始代码依赖于非标准扩展 __attribute__((packed)) 的方式。由于没有标准方法要求 struct 完全没有填充,因此将结构复制到缓冲区中的唯一符合标准的方法是单独复制每个成员。

这启发了我编写一个 c++11 助手来将可变数量的变量复制到 char 数组中。为了帮助使用它,一个帮助器来计算这些变量的总大小(已经完成here)。使用这些帮助程序,您可以轻松地将 struct 的成员复制到缓冲区中,而无需打包 struct

// variadic sizeof
// mostly same as https://stackoverflow.com/a/12666815/2079303
constexpr std::size_t sizeof_all() {
    return 0;
}
template <typename Head, typename... Tail>
constexpr std::size_t sizeof_all(const Head& head, const Tail&... tail) {
    return sizeof head + sizeof_all(tail...);
}

// variadic memcpy
void memcpy_all(char*) {}
template <typename Head, typename... Tail>
void memcpy_all(char* out, const Head& head, const Tail&... tail) {
    auto offset = sizeof head;
    std::memcpy(out, &head, offset);
    memcpy_all(out + offset, tail...);
}

// to use
packet p;
std::size_t buffer_size = sizeof_all(p.id, p.something, p.flags) + payload_size;
char* data = new char[buffer_size];
memcpy_all(data, p.id, p.something, p.flags);

现在,您只需要关心字节序即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多