从 QByteArray 以 bigendian 格式获取浮点数组的有效方法

Posted

技术标签:

【中文标题】从 QByteArray 以 bigendian 格式获取浮点数组的有效方法【英文标题】:Efficient way to get float array from QByteArray with bigendian format 【发布时间】:2017-01-13 10:09:16 【问题描述】:

我有一个 BigEndian 格式的 QbyteArray 变量 我想以最少的过程从该变量中获取一个浮点数组。 最快的方法是什么?

现在我正在使用以下代码,但效率不高,我认为应该有更好的方法?

请帮忙

float getValue(QByteArray dataBytes, int i)    
    QByteArray data = dataBytes.mid(i*4, 4);
    qint32 level = qFromBigEndian<qint32>((uchar*)data.data());
    float result = level*1.0;


float *f = new float[20];
for (int i=0;i<20;i++)
     f[i] = getValue(myDataBytes, i);

【问题讨论】:

问题1:编码的数字是整数吗?问题2:你希望它便携吗? 只是检查:QByteArray 包含qint32,并且您想将每个 BigEndian 整数转换为常规浮点数?请注意,这会失去精度。你需要一个double 来代表所有可能的qint32 【参考方案1】:

为什么不创建一个迭代器并构建一个std::vector?不损失效率且完全安全:

#include <cstdint>
#include <algorithm>
#include <vector>
#include <iterator>

// simulate types
using qint32 = std::int32_t;

struct QByteArray 
  QByteArray mid(int, int);
  const std::uint8_t* data() const;
  const std::size_t* size() const;
;

// simulate functions
template<class T> T qFromBigEndian(const std::uint8_t*);

// iterator to convert big endian byte streams to ints
struct big_endian_ints_iterator 
  : std::iterator<std::forward_iterator_tag, std::int32_t>


  big_endian_ints_iterator(const std::uint8_t * p) : ptr_(p) 

  big_endian_ints_iterator& operator+=(std::size_t i) 
    ptr_ += 4 * i;
    return *this;
  

  big_endian_ints_iterator& operator++() 
    ptr_ += 4;
    return *this;
  

  big_endian_ints_iterator operator++(int) 
    auto tmp = *this;
    ptr_ += 4;
    return tmp;
  

  value_type operator*() const 
    return qFromBigEndian<std::int32_t>(ptr_);
  

  bool operator!=(const big_endian_ints_iterator& r) const 
    return r.ptr_ != ptr_;
  

  bool operator==(const big_endian_ints_iterator& r) const 
    return r.ptr_ == ptr_;
  

  const std::uint8_t* ptr_;
;

big_endian_ints_iterator operator+(big_endian_ints_iterator l, std::size_t r)

  return l += r;


std::vector<float> test(QByteArray const& myDataBytes)

  auto first = big_endian_ints_iterator(myDataBytes.data());
  std::vector<float> f(first, first + 20);
  return f;

godbolt 上的证明:https://godbolt.org/g/PG3H2V

【讨论】:

如何做到“完全安全”?您的代码仅进行指针运算,并不比问题中的代码更安全。试试 `std::vector f(first, first + 21);` 你会有 _ptr 指向 QByteArray 缓冲区之后,可能在未分配的内存中。 @BenjaminT 我的意思是就浮动向量的管理而言是安全的。我不熟悉 QByteArray,但我确信在初始化向量之前必须有一种方法来检查它的长度。【参考方案2】:

快速回答,删除对QByteArray::mid() 的调用并仅使用const 函数来防止额外的写时复制。除此之外,我认为您无法提高效率,也许是内联函数。

inline float getValue(const QByteArray &dataBytes, int i)  
    const qint32 level = qFromBigEndian<qint32>(&static_cast<const qint32 *>(dataBytes.constData())[i]);
    return level*1.0;

【讨论】:

以上是关于从 QByteArray 以 bigendian 格式获取浮点数组的有效方法的主要内容,如果未能解决你的问题,请参考以下文章

从 QByteArray 解析 QT5 JSON

从 QBytearray 创建 QImage

从作为 QString 输入的 HEX 值构造 QByteArray

如何从数据库文件中创建 QByteArray

从QDataStream向QByteArray中写入数据时的注意点(QT)

Qt 从QByteArray类型数据恢复long in型数据