【问题标题】:Extracting an int from slice of std::vector<unsigned char>? [duplicate]从 std::vector<unsigned char> 的切片中提取一个 int? [复制]
【发布时间】:2018-10-22 05:38:54
【问题描述】:

我正在解析二进制标头 (std::vector&lt;unsigned char&gt;),需要提取四个无符号整数。

我有时还需要提取unsigned short(对于其他标头),因此更可取的是通用解决方案。

如何将 std::vector 的切片转换为整数?

这是我尝试过的:

class PacketHeader {
public:
    static const unsigned short LENGTH = 16;

    PacketHeader(std::vector<unsigned char> &binary_data) {
      this->timestamp_seconds = ntohs(*reinterpret_cast<const unsigned int *>(&binary_data[0]));
      this->timestamp_ms_or_ns = ntohs(*reinterpret_cast<const unsigned int *>(&binary_data[4]));
      this->packet_data_length = ntohs(*reinterpret_cast<const unsigned int *>(&binary_data[8]));
      this->untruncated_packet_data_length = ntohs(*reinterpret_cast<const unsigned int *>(&binary_data[12]));
    }

    unsigned int get_timestamp_seconds();
    unsigned int get_timestamp_ms_or_ns();
    unsigned int get_packet_data_length();
    unsigned int get_untruncated_packet_data_length();
private:
    unsigned int timestamp_seconds;
    unsigned int timestamp_ms_or_ns;
    unsigned int packet_data_length;
    unsigned int untruncated_packet_data_length;
};

【问题讨论】:

  • 谨防严格的别名规则。
  • 我强烈建议编写一个序列化器/反序列化器,用于将数据打包到字节的 std::vector 中,而不是手动将每个成员变量重新解释为字节位置 x。它不仅允许您序列化任何数据,还允许序列化其他类/结构中的类/结构 - 自动

标签: c++


【解决方案1】:

当然,在我发布这个问题之后,我找到了一个可行的解决方案。

这是我从here找到的:

template <typename T>
T extract(const vector<unsigned char> &v, int pos)
{
  T value;
  memcpy(&value, &v[pos], sizeof(T));
  return value;
}

【讨论】:

  • 不是字节序依赖吗?
【解决方案2】:

创建一个序列化器/反序列化器以自动将数据打包到字节数组中。下面我快速创建了一个序列化器,它只序列化整数类型。您可以将其扩展到字符串、向量、其他对象(使用递归)。

using Buffer = std::vector<int>;

/*! 
 * Serialise all primitive data types (Intergrals: 8, 16, 32, 64)
 */
template <typename T>
void serialise(Buffer& buffer, uint32_t& offset, const T& data)
{
    uint32_t size = sizeof(data);           // Get size for memcpy
    buffer.resize(buffer.size()+size);      // Ensure data will fit
    memcpy( &buffer[offset], &data, sizeof(data) ); // Copy data (use ntohs aswell)
    offset += size;                         // Increase offset for next item
}

/*!
 * Primitive Serialiser class which should be applied to elements in a visitor-
 * pattern type construct. Fills buffer with packed binary data of elements.
 */
class Serialiser
{
    public:
        Buffer& buffer;   // resulting byte buffer (just a std::vector<uint8_t>)
        uint32_t offset;  // offset use internally

    public:
        Serialiser(Buffer& _buffer) : buffer(_buffer), offset(0)
        {}

        // Serialise singular data type
        template <typename T>
        operator() (const T& data)
        {
            serialise(buffer, offset, data);
        }

};

现在使用它!

struct PacketHeader
{
    private:
        uint32_t timestamp_seconds;
        uint32_t timestamp_ms_or_ns;

    public:
        PacketHeader()=default;
        // .. Extra constructors if you want?

    private:
        template<typename SER>
        void serialise(SER& ser)
        {
           ser(timestamp_seconds);
           ser(timestamp_ms_or_ns);
        }
};

int main()
{
    // Create Packet Struct with data?
    PacketHeader packet(...);

    Buffer buffer;
    Serialiser serialiser(buffer);

    // Serialise the packet INTO the buffer
    packet.serialise(serialiser);

    // DONE! Read data out
    // .. print bytes of buffer

    return 0;
}

因此,Serialiser 类通过 PacketHeader::serialise 方法将其 () 运算符应用于数据包类中的每个成员变量。它应用运算符的每个方法,都会将该变量复制到 std::vector(缓冲区)中。

要反序列化,您只需创建一个执行反向 memcpy 的反序列化器类,packetHeader 类不需要更改。

【讨论】:

    猜你喜欢
    • 2012-03-07
    • 1970-01-01
    • 2018-12-02
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    • 2021-08-11
    • 2013-11-18
    相关资源
    最近更新 更多