Есть ли более короткий способ инициализации QByteArray?

В моей программе я много работаю с последовательной связью, поэтому QByteArray используется очень часто.

Мне было интересно, есть ли более короткий способ инициализировать QByteArray определенными байтами, чем:

const char test_data[] = {
    static_cast<char>(0xB1), static_cast<char>(0xB2),
    0x5, static_cast<char>(0xFF),
    static_cast<char>(0xEE), static_cast<char>(0xEE),
    static_cast<char>(0x0)}; // Note QByteArray should be able to hold 0 byte
const QCanBusFrame frame = QCanBusFrame(0xA1, QByteArray(test_data));

static_cast<char> необходим, потому что в противном случае C++11 выдает ошибку о сужении, потому что диапазон от 0x7F до 0xFF больше, чем может поместиться char, но char — это то, что запрашивает конструктор QByteArray.

Это используемый конструктор QByteArray:

QByteArray::QByteArray(const char *data, int size = -1)


person DBedrenko    schedule 31.03.2016    source источник
comment
Что происходит, когда вы объявляете test_data как массив символов без знака (unsigned char*), а затем приводите его к массиву символов (char*)?   -  person OnurA    schedule 31.03.2016
comment
@OnurA Вы уверены, что звездочку нужно использовать? Строка, которая инициализирует test_data, выдает недопустимое преобразование из 'int' в 'const unsigned char*   -  person DBedrenko    schedule 31.03.2016
comment
Вы можете легко создать функцию, которая создает QByteArray с тем, что вы хотите в качестве аргумента.   -  person Garf365    schedule 31.03.2016
comment
может ли любое из ваших значений байта быть 0x00 - если нет, вы можете использовать конструктор const char* со строковым литералом   -  person Jimmy    schedule 31.03.2016
comment
Извините за путаницу, массив на самом деле является указателем, что я и имел в виду. В вашем случае это должно быть: const unsigned char test_data[] = {...} Тогда вам, вероятно, следует использовать: QByteArray((char*)test_data)   -  person OnurA    schedule 31.03.2016
comment
@ Garf365, ха-ха .... очевидное решение, но я об этом не подумал. Вот так и сделаю, спасибо!   -  person DBedrenko    schedule 31.03.2016
comment
@SpaghettiCat Не за что ;)   -  person Garf365    schedule 31.03.2016
comment
@Джимми, но я бы не стал полагаться на возможность того, что один из байтов может/не может быть 0x00   -  person OnurA    schedule 31.03.2016
comment
@Jimmy Джимми. Вы правы, \x01\xB2\xB4 можно передать в конструктор, но гораздо лучше работать с целыми числами (вы можете использовать имена констант и т. д.). Я должен быть в состоянии иметь 0 байт, хотя...   -  person DBedrenko    schedule 31.03.2016


Ответы (6)


Просто и эффективно:

QByteArray b = QByteArrayLiteral("\x12\x00\xa4\x42\x51\x00\x00\x99");
person peppe    schedule 31.03.2016
comment
Хм, я нигде не вижу QByteArrayLiteral задокументированного, но, ей-богу, он работает лучше, чем точно такой же аргумент, переданный QByteArray, потому что \x00 не рассматривается как разделитель строки. То же самое можно сделать с помощью QByteArray, но вы должны передать правильный аргумент size. Не плохое решение, спасибо :) - person DBedrenko; 31.03.2016
comment
@DBedrenko Это просто макрос: doc.qt.io/qt-5/qbytearray .html#QByteArrayLiteral - person rbaleksandar; 25.10.2017
comment
Интересно, кто задокументировал это... - person peppe; 25.10.2017
comment
Присутствует только начиная с Qt5 - person garlix; 17.04.2018
comment
Любая другая основная версия Qt достигла EOL. - person peppe; 17.04.2018

В качестве альтернативы QByteArrayLiteral при желании можно накатить свой:

#include <QByteArray>

template <int N> QByteArray arrayFromLiteral(const char (&data)[N]) {
   return QByteArray::fromRawData(data, N-1);
}

int main() {
   const auto arr = arrayFromLiteral("\xB1\xB2\0\1");
   Q_ASSERT(arr.size() == 4);
   Q_ASSERT(arr[0] == (char)0xB1);
   Q_ASSERT(arr[1] == (char)0xB2);
   Q_ASSERT(arr[2] == (char)0x00);
   Q_ASSERT(arr[3] == (char)0x01);
}
person Kuba hasn't forgotten Monica    schedule 31.03.2016

Может быть работает медленно:

QByteArray ba = QByteArray::fromHex(QVariant("B1B2FFEEEE00").toByteArray());
person Andrey Reeshkov    schedule 31.01.2017

как это:

const unsigned char str[] = {0xff, 0xed, 0xba, 0xd1};
QByteArray ba(reinterpret_cast<const char*>(&str[0]),std::extent<decltype(str)>::value);

теперь конструктор QByteArray выглядит странно, но последовательности байтов понятны. Вы также можете добавить завершающий 0-байт к массиву вместо использования std::extent, но в целом вы можете иметь нулевые байты в середине последовательности.

person Andrei R.    schedule 31.03.2016
comment
Просто из любопытства не могли бы вы объяснить, зачем нужны reinterpret_cast и std::extent? - person OnurA; 31.03.2016
comment
Мне нравится reinterpret_cast (стиль C++, а не C). Вместо экстента просто используйте sizeof(str)... - person Aconcagua; 31.03.2016
comment
Разве вы не можете просто использовать str вместо &str[0] (выглядит некрасиво для меня)? По крайней мере, GCC принимает... - person Aconcagua; 31.03.2016

Вдохновленный ответами выше, вот что я наконец придумал:

const quint8 testData[] {0xB1, 0x00, 0xB2, 0x00};
const QCanBusFrame cFrame = QCanBusFrame(
    0xA1, QByteArray(reinterpret_cast<const char*>(testData), sizeof(testData)));

Я предпочитаю иметь байты в виде чисел байтов, а не буквальных символов при работе с последовательной связью.

После обсуждения ##c++ мне посоветовали использовать reinterpret_cast в этой ситуации.

person DBedrenko    schedule 31.03.2016

Вы пробовали следующее:

const unsigned char test_data[] = {
    static_cast<char>(0xB1), static_cast<char>(0xB2),
    0x5, static_cast<char>(0xFF),
    static_cast<char>(0xEE), static_cast<char>(0xEE),
    static_cast<char>(0xB3)};
const QCanBusFrame frame = QCanBusFrame(0xA1, QByteArray((char*)test_data));

Вы используете конструктор: QByteArray::QByteArray(const char *data, int size = -1).

Если размер отрицательный, предполагается, что данные указывают на строку с завершающим нулем, и ее длина определяется динамически. Завершающий нулевой символ не считается частью массива байтов.

person OnurA    schedule 31.03.2016
comment
Я только что попробовал, и он успешно компилируется. Он работает без всех static_cast (все преимущество вашего решения в том, что эти приведения не нужны). Я не уверен, что мне следует быть осторожным с 0 байтами: мне также нужно иметь возможность использовать 0 байтов. - person DBedrenko; 31.03.2016
comment
Вам обязательно нужно позвонить QByteArray((char*) test_data, sizeof(test_data));! Ctor с одним параметром (или с размером == -1) попытается скопировать данные как обычную c-строку, которая должна заканчиваться нулем! - person Aconcagua; 31.03.2016
comment
Вероятно, если у вас есть 0x00 в середине, он обнаружит его как конец вашего массива символов. Вот почему я бы передал размер массива в качестве аргумента - person OnurA; 31.03.2016
comment
Это мое любимое решение, но приведение в стиле C не очень хорошо. Сейчас я пытаюсь найти способ как-то использовать static_cast. - person DBedrenko; 31.03.2016