1

我正在尝试构建和编写一个二进制请求并有一个“这可能”类型的问题。对我来说重要的是要提到请求的接收者不知道我在下面包含的数据结构,它只是期望一个字节序列,但是使用结构似乎是准备请求片段的一种方便方法,然后轻松地编写它们。

编写页眉和页脚很好,因为它们是固定大小的,但是由于矢量,我遇到了结构“详细信息”的问题。现在我正在写入一个文件,所以我可以检查请求是否符合规范,但目的是最终使用 boost asio 串行端口写入 PLC

我可以使用这样的语法来编写一个结构,但是当它到达向量时会写入指针地址而不是值

myFile.write((char*) &myDataRequest, drSize);

我可以使用此语法自行编写向量,但我必须在 0 处包含索引器才能写入值

myFile.write((char*) &myVector[0], vectorSize);

有没有一种优雅的方法来二进制编写一个包含向量(或其他合适的集合)的结构,一次完成?例如,如果我以不同的方式声明了向量,或者我是否愿意为结构内的内容进行多次写入。如果我用数组替换向量,我可以一次性发送结构(不需要包含任何索引器),但直到运行时我才知道所需的大小,所以我认为它不合适。

我的结构

    struct Header
    {   ...     };

    struct Details
    {
           std::vector<DataRequest> DRList;
    };

    struct DataRequest
    {
           short numAddresses;          // Number of operands to be read   Bytes 0-1
           unsigned char operandType;   //                                  Byte 2
           unsigned char Reserved1;     //Should be 0xFF                    Byte 3
           std::vector<short> addressList;  // either, starting address (for sequence), or a list of addresses (for non-sequential) 
    };

    struct Footer
    {   ...     };
4

3 回答 3

2

这是不可能的,因为该std::vector对象实际上并不包含一个数组,而是一个指向内存块的指针。但是,我很想声称能够编写这样的原始结构是不可取的:

  1. 我相信通过将结构视为一块内存,您最终可能会发送填充字节,我认为这是不可取的。

  2. 根据您写入的内容,您可能会发现写入无论如何都会被缓冲,因此多次写入调用实际上并没有降低效率。

  3. 您可能想对发送过来的字段做一些事情。特别是,对于您发送的数值。这需要强制执行传输双方都同意的字节顺序。为了便于移植,您应该明确转换字节顺序以确保您的软件是可移植的(如果需要的话)。

长话短说:我怀疑一个一个地写出每个字段的效率并没有降低,它也更正确。

于 2012-09-25T12:42:41.313 回答
1

这不是一个真正的好策略,因为即使您可以这样做,您也会将内存内容直接复制到文件中。如果您更改架构/处理器,您的客户将获得不同的数据。如果您编写一个采用结构和文件名的方法,该方法单独写入结构值并遍历向量写出其内容,您将完全控制客户端期望的二进制格式,并且不依赖于编译器当前内存表示。

如果你想方便编组/解组,你应该看看boost::serialization库。他们确实提供了二进制存档(除了文本和 xml),但它有自己的格式(例如,它有一个版本号,用于转储数据的序列化库)所以它可能不是您的客户想要的。

于 2012-09-25T12:42:12.157 回答
1

另一端预期的格式到底是什么?你必须写那个,期间。你不能只写任何随机字节。只写一个你正在做的事情的概率std::vector大约是你能得到的接近于 0 的概率。struct但是只写一个 with会起作用的概率 int仍然低于 50%。如果对方期望一个特定的字节序列,那么您必须逐字节地编写该序列。例如,要编写一个int,您仍然必须编写四个(或任何协议要求的)字节,例如:

byte[0] = (value >> 24) & 0xFF;
byte[1] = (value >> 16) & 0xFF;
byte[2] = (value >>  8) & 0xFF;
byte[3] = (value      ) & 0xFF;

(即使在这里,我假设您对负数的内部表示对应于协议的表示。通常是这种情况,但并非总是如此。)

当然,通常情况下,您在 a 中构建缓冲区std::vector<char>,然后写入&buffer[0], buffer.size(). (你需要一个缓冲区指针的事实 reinterpret_cast应该表明你的方法是错误的。)

于 2012-09-25T12:51:43.320 回答