【问题标题】:how to store data from std::vector<short> in std::vector<uint8_t>如何将来自 std::vector<short> 的数据存储在 std::vector<uint8_t> 中
【发布时间】:2017-08-21 21:23:50
【问题描述】:

我想要做的是将数据存储在std::vector&lt;short&gt; 中的std::vector&lt;uint8_t&gt; 中,将每个short 分成两个uint8_t 值。我需要这样做,因为我有一个只会发送std::vector&lt;uint8_t&gt; 的网络应用程序,所以我需要转换为 uint8_t 发送,然后在收到 uint8_t 向量时转换回来。

通常我会做的(以及我在查找问题时看到的)是:

std::vector&lt;uint8_t&gt; newVec(oldvec.begin(),oldvec.end());

但是,如果我理解正确,这将采用每个单独的短值,截断为 uint8_t 的大小,并创建一个包含一半数据量和相同条目数的新向量,而我想要的是相同的具有两倍条目的数据量。

包含一种方法来逆转该过程并尽可能避免复制的解决方案将有很大帮助。谢谢!

【问题讨论】:

  • 只是memcpy data() 从一个到另一个?
  • 不错,@VTT,但为一些端序怪异留出了空间。
  • 花点时间校对你写的东西。 store the data in a std::vector in a std::vector 这样的短语不太可能引起同情。
  • @Mikhail 相关的差异隐藏在 angulars 中。我进行了编辑以使其可见。
  • @DavidSchwartz 我将使用大端序,所以短的 0000000000000001 将作为两个条目存储在 uint8_t 向量中,00000000 和 00000001。理论上我不应该处理字节序问题因为代码总是在同一台计算机上运行,​​并且我可以控制序列化和反序列化,但我正在努力使其尽可能便携。我不确定如何在不知道字节顺序的情况下在具有不同字节顺序的机器上正确重建短裤。有一个关于重建检查字节顺序的 if 语句?

标签: c++ vector


【解决方案1】:

要在 8 位边界分割某些东西,您可以使用右移和掩码,即

uint16_t val;
uint8_t low = val & 0xFF;
uint8_t high = (val >> 8) & 0xFF;

现在您可以将您的最高价和最低价放入您订单中的第二个向量中。

【讨论】:

    【解决方案2】:

    对于拆分和合并,您将拥有以下内容:

    unsigned short oldShort;
    uint8_t char1 = oldShort & 0xFF; // lower byte
    uint8_t char2 = oldShort >> 8; // upper byte
    

    然后将这两个部分推到向量上,并将其发送到您的网络库。在接收端,在重新组装期间,您将从向量中读取接下来的两个字节并将它们组合回短。

    注意:确保接收到的向量上有偶数个元素,这样您就不会在传输过程中获得损坏/修改的数据。

    // Read off the next two characters and merge them again
    unsigned short mergedShort = (char2 << 8) | char1;
    

    【讨论】:

      【解决方案3】:

      我需要这样做,因为我有一个网络应用程序1,它只会发送 std::vector 的

      除了掩码和位移之外,您在通过网络发送内容时还应该考虑字节序。

      数据的网络表示通常是big endian。因此,您始终可以将 MSB 放在首位。提供一个简单的函数,如:

      std::vector<uint8_t> networkSerialize(const std::vector<uint16_t>& input) {
          std::vector<uint8_t> output;
          output.reserve(input.size() * sizeof(uint16_t)); // Pre-allocate for sake of
                                                           // performance
          for(auto snumber : input) {
              output.push_back((snumber & 0xFF00) >> 8); // Extract the MSB
              output.push_back((snumber & 0xFF)); // Extract the LSB
          }
          return output;
      }
      

      并像使用它

      std::vector<uint8_t> newVec = networkSerialize(oldvec);
      

      live demo


      1)强调我的

      【讨论】:

      • 你应该考虑在进入循环之前调用output.reserve(input.size() * sizeof(uint16_t))
      • @RemyLebeau 好主意,采纳。
      【解决方案4】:

      免责声明:人们在谈论“网络字节顺序”。如果您发送大于 1 字节的内容,当然需要take network endiannes into account。但是,据我了解限制“仅发送std::vector&lt;uint8_t&gt; 的网络应用程序” 明确指出“我不想弄乱任何字节序”时间>。 uint8_t 已经是一个字节,如果您按一个顺序发送一系列字节,您应该以完全相同的顺序将它们取回。这很有帮助:sending the array through a socket.
      客户端和服务器机器上可能有不同的系统字节序,但 OP 对此只字未提,所以这是一个不同的故事......

      关于答案: 假设所有“字节顺序”问题都已关闭。 如果您只是想发送一个短裤矢量,我相信,VTT 的答案会表现最好。但是,如果std::vector&lt;short&gt; 只是一个特例,您可以使用my answer to a similar question 中的pack() 函数。它将任何可迭代的容器、字符串、C 字符串等打包成一个字节向量,并且不执行任何字节序。
      只需包含byte_pack.h,然后您就可以使用它了像这样:

      #include "byte_pack.h"
      
      void cout_bytes(const std::vector<std::uint8_t>& bytes)
      {
          for(unsigned byte : bytes) {
              std::cout << "0x" << std::setfill('0') << std::setw(2) << std::hex
                         << byte << " ";
          }
          std::cout << std::endl;
      }
      
      
      int main()
      {
          std::vector<short> test = { (short) 0xaabb, (short) 0xccdd };
          std::vector<std::uint8_t> test_result = pack(test);
      
          cout_bytes(test_result); // -> 0xbb 0xaa 0xdd 0xcc (remember of endianness)
      
          return 0;
      }
      

      【讨论】:

        【解决方案5】:

        只需一次复制所有内容:

        ::std::vector<short> shorts;
        // populate shorts... 
        ::std::vector<uint8_t> bytes;
        ::std::size_t const bytes_count(shorts.size() * sizeof(short) / sizeof(uint8_t));
        bytes.resize(bytes_count);
        ::memcpy(bytes.data(), shorts.data(), bytes_count);
        

        【讨论】:

        • “请注意,这种方法不会以任何方式处理字节顺序,因为问题中没有提到它。” 提到 network 传输意味着.
        • @user0042 不,仅提及 network 传输并不意味着任何方式。此外,network 并不意味着数据应该在网络中传输或像其他帖子所暗示的任何其他特定字节顺序。也不意味着应用程序在 Little Endian 平台上运行。因此,其他问题中建议的字节顺序翻转实际上可能会破坏原始的 Big Endian 顺序。
        • 如果需要,您可以随时返回vector&lt;uint8_t&gt; 应用字节序转换,例如:for (int i = 0; i &lt; bytes.size(); i += sizeof(short)) { short *s = reinterpret_cast&lt;short*&gt;(&amp;bytes[i]); *s = htons(*s); }
        • 有人能解释一下这个答案在哪里不好吗?给定连接的内部大字节序如何改变电线另一端的输出?如果您使用任何正常的网络连接发送“0x1、0x2、0x3、0x4”,您将收到“0x1、0x2、0x3、0x4”我错了吗?
        • @WindyFields 这个答案还不错,因为它回答了给定的问题,而没有对底层协议和应用程序要求的字节序处理进行疯狂猜测。例如,如果发送方机器是小字节序而接收方机器是大字节序,则可能会出现字节序问题。发送 1234 短将被接收为 3364。因此,要在这两台机器之间传输二进制数据,程序员需要定义在他正在实现的数据交换协议中如何处理字节序。然而,“以网络字节顺序发送所有内容”只是可能的方法之一。
        猜你喜欢
        • 2020-11-19
        • 2017-05-13
        • 1970-01-01
        • 2020-12-09
        • 1970-01-01
        • 2015-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多