添加(而不是连接)一个数字到 QByteArray

Add(not concatenate) a number to QByteArray

我有以下 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)而不是执行实际操作。如何做到这一点?

首先: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 '[=10=]' bytes to the array to fill it up to an N byte length
    if(dSize < maxSize)
        data = QByteArray{maxSize - dSize, '[=10=]'} + 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 - 而不是未签名的整数。

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

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

这实际上取决于这些数据的来源和使用方式。

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

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;

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

为什么不使用像

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

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