【问题标题】:Add(not concatenate) a number to QByteArray添加(不连接)一个数字到 QByteArray
【发布时间】:2019-04-19 09:53:39
【问题描述】:

我有以下QByteArray

QByteArray ba;
ba.resize(3);
ba[0]=ba[2]=0x8a;
ba[1]=0x0d;          //so ba=8a0d8a

我想在上面的QByteArray 中添加一个十六进制数。例如。在添加 0x01 时,ba 应该包含 8a0d8b。任何此类涉及进位的操作都应该像正常的十六进制加法一样向前传播。我试过使用+ 运算符:

ba=ba+1;

但它连接(在上述情况下导致8a0d8a01)而不是执行实际操作。这是怎么做到的?

【问题讨论】:

  • 字节数组应该总是三个元素吗?
  • 它可以有 3 或 4 个元素。不多了
  • 但是也许最好写一个类来直接存储和操作数字,并在需要时将它们作为字节数组返回?
  • 我希望有一些内置功能来做到这一点。否则我可以在 for 循环中进行更手动的字节添加,但这意味着不必要地使代码复杂化
  • 你真的需要在 QByteArray 上做数学吗?为什么不这样做,让我们说长并转移到需要的位置?

标签: c++ qt qt5 qbytearray


【解决方案1】:

我认为这是最简单的解决方案:

uint32_t num = (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + (b[0]);
num++; // add one
b[0] = num & 0xff;
b[1] = (num >> 8) & 0xff;
b[2] = (num >> 16) & 0xff;
b[3] = (num >> 24) & 0xff;

基本上你来回转换为算术整数。只要确保你没有溢出。这是一个简单的例子。您可以将其设为具有在某个方法上返回 QByteArray 的状态的类,或者您可以创建一次执行此操作的函数。

【讨论】:

  • 一个简单的解决方案,只要数据的字节顺序无关紧要
  • @Felix 该操作提供大端数据,这是我们所关心的。您正在引入一个不存在的问题。
【解决方案2】:

首先:QByteArray 中没有这样的功能。但是,有很多方法可以解决它,只要您知道字节数组的长度。然而,有一件小事让这件事变得更加复杂:Endianess

以下示例假定所有字节数组都有最大长度。该函数是通用的,因此您可以根据需要动态决定:

template <typename TInt>
void addNumber(QByteArray &data, TInt number) {
    static_assert(std::is_integral<TInt>::value, "TInt must be an integral type");

    constexpr auto maxSize = sizeof(TInt);
    const auto dSize = data.size();

    // make shure no data that is longer then the allowed integer size is passed
    Q_ASSERT_X(dSize <= maxSize, Q_FUNC_INFO, "bytearrays longer than sizeof(TInt) byte are not allowed!");

    // prepend '\0' bytes to the array to fill it up to an N byte length
    if(dSize < maxSize)
        data = QByteArray{maxSize - dSize, '\0'} + data;

    // convert to a number, add and convert back
    auto dataNum = qFromBigEndian<TInt>(data.constData());
    dataNum += number;
    qToBigEndian(dataNum, data.data());

    // resize the data back to the original size, dropping the previously prepended bytes
    if(dSize < maxSize)
        data = data.mid(maxSize - dSize);
}

要使用该方法,只需找出您的字节数组可以有多长,然后使用相应类型的方法。例如,如果您的数据限制为最多 4 个字节(如评论中所述),您可以将其用作:

QByteArray ba = "\x8a\x0d\x8a";
addNumber<quint32>(ba, 1u);
// ba is now "\x8a\x0d\x8b"

重要提示:小心使用模板参数。明确指定它以确保您不会意外传递不同类型的文字。例如,将其简单地称为 addNumber(ba, 1) 会将 TInt 推导出为 int - 而不是一个未指定的 int。

编辑: 如果您将 bytearrays 字节序定义为与当前平台相同,则不需要进行此类转换。代码将更改为:

// convert to a number, add and convert back
*(reinterpret_cast<TInt*>(data.data())) += number;

这实际上取决于这些数据的来源以及您如何使用它。

【讨论】:

  • 这里没有字节序问题...它是一个字节数组
  • @TheQuantumPhysicist 数字具有由平台定义的字节序,字节数组具有由 OP 定义的字节序。它们可能不同
  • @Caleth 看看我的解决方案,看看字节序如何无关紧要,除非你做到了。
  • @TheQuantumPhysicist "它可以有 3 或 4 个元素" 你的回答假设为 4。这不是。
  • @Caleth 为什么字节序是 3 还是 4 很重要?我的答案适用于两者,因为第四个字节可以为零。这是一个概念证明。你可以把它放在一个循环中,让它变得各种花哨。
【解决方案3】:

为什么不使用像

这样的简单数据
template <typename T> union BData
{
     uint8_t data[sizeof(T)];
     T value;
 }; 

然后您可以执行算术运算并从联合中提取字节。但是,您应该注意 endiness。

【讨论】:

    猜你喜欢
    • 2012-12-01
    • 2020-04-25
    • 1970-01-01
    • 2013-11-16
    • 2018-04-14
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-04-28
    相关资源
    最近更新 更多