向QByteArray添加(而不是串联)数字

时间:2018-11-16 08:23:51

标签: c++ qt qt5 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)而不是执行实际操作。该怎么办?

3 个答案:

答案 0 :(得分:1)

首先,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"

重要:请谨慎使用template参数。明确指定它,以确保您不会意外地传递其他类型的文字。例如,简单地将其命名为addNumber(ba, 1)会得出TIntint的含义-而不是未整数的整数。

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

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

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

答案 1 :(得分: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的类,也可以使函数一次执行一次此操作。

答案 2 :(得分:0)

为什么不使用像

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

然后,您可以执行算术运算并从并集提取字节。但是,您应该注意耐力。