【问题标题】:Data Structure to represent command packet format表示命令包格式的数据结构
【发布时间】:2019-05-12 15:40:29
【问题描述】:

我的目的是构建一个配置文件。所以我基本上必须以某种方式表示命令包结构。

当实际数据(二进制)到来时,我想将数据包与此配置文件进行比较,然后对其进行处理(将数据转换为 CSV 格式)。

所以有不同的命令类型。

所以每次收到一个数据包时,我都必须获取它的操作码并用配置文件检查它并返回代表该数据包格式的适当命令格式。

命令格式可能如下所示:

操作码 - 1 个字节 - 整数

命令 - 4 字节 - 字符串

...

所有命令的字段数或格式不同。

我想检索所有这些详细信息。我可以用 XML 表示它并使用 libxml2 之类的库对其进行解析。

下面给出了一个示例 XML 格式:

 <cmd type="Multiplication">
    <field name="opcode" type="string" bytes="4"/>
    <field name="Multiplicand" type="number" bytes="2"/>
    <field name="Multiplier" type="number" bytes="2"/>
 </cmd>

但这种方法相当缓慢。

我的想法是以某种方式在结构中表示命令包格式。但由于 C/C++ 不是反射语言,因此无法知道结构成员,并且您需要每个结构(命令)一个函数来解析它。

请提出一些存储格式的方法,这样一个通用函数就可以通过查看这种格式来解析二进制数据。

  • 语言可以是 C 或 C++。
  • 性能是重中之重,因此不鼓励使用 XML 和类似类型。
  • 内存中的数据结构是首选。

非常感谢任何帮助。

【问题讨论】:

  • 该数据结构的格式与解析后的处理方式相关,而不是解析本身。没有这些信息,很难回答这个问题。否则,答案就是:memcpy() 它在一个字节向量中,这可能不是你想要的。
  • 我必须通过查看数据包格式将二进制数据解析为 csv 文件。
  • 除了使用std::variant之外,我还需要说更多吗?
  • 我同意 std::variant 在这种情况下可能是最好的解决方案,但我认为以前没有见过它的人可能需要更多关于如何使用它的解释。许多人第一次看到它时,他们的第一个倾向是使用 std::get 或 std::try_get(它们很麻烦)而不是仅仅使用 std::visit。即使是有经验的 C++ 用户,我也看到了这一点

标签: c++ c data-structures


【解决方案1】:

我认为最好的办法是将文件表示为正确命令类型的variants 的集合。例如,假设您有三个命令选项:

struct Constant {
    short value;
};
struct UnaryOperation {
    unsigned char opcode;
    short value;
};
struct BinaryOperation {
    unsigned char opcode;
    short value1;
    short value2;
};

表示未知命令。如果您有未知命令,可以将其表示为三种类型的variant

using Command = std::variant<Constant, UnaryOperation, BinaryOperation>; 

根据命令类型应用函数。假设每个命令都有不同的函数:

short eval(Constant c) {
    return c.value;
}
short eval(UnaryOperation u) {
    switch(u.opcode) {
        // stuff
    }
}
short eval(BinaryOperation b) {
    switch(b.opcode) {
        // stuff
    }
}

我们可以使用std::visit 来评估任意的Command

short evaluate_command(Command const& command) {
    short output; 
    // This calls the right overload automatically 
    std::visit(command, [&](auto cmd) { output = eval(cmd); }); 
    return output; 
}

解析命令。 我们可以根据定义的任何类型自动创建std::variant。这意味着,如果您提供一种方法来确定基于文件的命令是什么,那么这很容易做到。

enum class OpType : unsigned char {
    ConstantOp, UnaryOp, BinaryOp
};
// Command can be automatically constructed from a Constant, a UnaryOperation, or a BinaryOperation
Command readFromStream(std::istream& i) {
    OpType type;
    unsigned char op;
    short value, value2;

    // Read the type of the operation
    i >> (unsigned char&)type;

    //Return either a Constant, a UnaryOperation, or a BinaryOperation
    switch(type) {
        case OpType::ConstantOp: {
             i >> value;
             return Constant{value};
        }
        case OpType::UnaryOp: {
            i >> op >> value;
            return UnaryOperation{op, value};
        }
        case OpType::BinaryOp {
            i >> op >> value >> value2;
            return BinaryOperation{op, value, value2}; 
        }
    }
}

【讨论】:

  • 这不是工厂设计模式吗?此外,我不想有单独的函数来解析每个命令,而是一个函数,它将命令元数据作为参数(结构)并根据它解析二进制文件。但是由于 C++ 不是一种反射语言,我不知道是否可以在不对其进行硬编码的情况下提取结构的内容(有关命令的元数据)。
  • 如果您将类型表示为元组,那么我可以向您展示如何根据元组中的类型自动解析二进制文件。 (这不仅适用于std::tuple - 任何将其内部数据类型基于模板参数列表的类型都可以使用)
猜你喜欢
  • 2018-03-07
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
相关资源
最近更新 更多