1939 / 1763 / 825
Регистрация: 23.01.2014
Сообщений: 6,211
1

Перевод Int/FLoat -> QByteArray -> Int/Float

23.10.2015, 11:18. Показов 6178. Ответов 11
Метки нет (Все метки)

Есть задача переводить float/int данные в бинарный вид и обратно (в последующем для передачи по сети или записи в бинарные файлы, формат Big-Endian, SinglePrecision для чисел с плавающей запятой). Вот так я реализовал функции перевода:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <QCoreApplication>
#include <QByteArray>
#include <QDataStream>
#include <QTextCodec>
#include <QTextStream>
 
QByteArray intToByteArray(qint32 input)
{
    QByteArray result(4, 0);
    QDataStream ds(&result, QIODevice::WriteOnly);
 
    ds << input;
 
    return result;
}
 
qint32 byteArrayToInt(const QByteArray& input)
{
    qint32 result {0};
 
    QDataStream ds(input);
 
    ds >> result;
 
    return result;
}
 
QByteArray floatToByteArray(float input)
{
    QByteArray result(4, 0);
 
    QDataStream ds(&result, QIODevice::WriteOnly);
    ds.setFloatingPointPrecision(QDataStream::SinglePrecision);
 
    ds << input;
 
    return result;
}
 
float byteArrayToFloat(const QByteArray& input)
{
    float result{.0};
 
    QDataStream ds(input);
    ds.setFloatingPointPrecision(QDataStream::SinglePrecision);
 
    ds >> result;
 
    return result;
}
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    QTextStream is(stdin, QIODevice::ReadOnly);
    QTextStream os(stdout, QIODevice::WriteOnly);
    os.setCodec("csIBM866");
 
    for (QString s = is.readLine();
         s.compare("q", Qt::CaseInsensitive) != 0;
         s = is.readLine())
    {
        int i{0};
        float f{0};
        QByteArray qba{0};
        bool ok{0};
        int oki{0}; // 0 - error, 1 - integer, 2 - float
 
        i = s.toInt(&ok);
        if (ok)
        {
            oki = 1;
            qba = intToByteArray(i);
            os << QString("Распознано как Integer.");
        }
        else
        {
            f = s.toFloat(&ok);
            if (ok)
            {
                oki = 2;
                qba = floatToByteArray(f);
                os << QString("Распознано как Float.");
            }
            else
            {
                os << QString("Ошибка! Введите число или q для выхода.");
            }
        }
 
        if (oki != 0)
        {
            os << endl;
 
            // Вариант №1
            os << QString(qba.toHex()) << endl;
            /* Выводит "000000ff", недостаток - нет возможности форматирования,
             * например если хочу чтобы выводило 0x00 0x00 0x00 0x0F
             */
 
            s = "";
 
            // Вариант №2
            for (const auto& c : qba)
                s.append(QString("0x%1 ")
                            .arg(QString::number((quint8)c, 16)
                                 .toUpper(), 2, QChar('0')));
 
            os << s << endl;
            /* Выводит "0x00 0x00 0x00 0x0F" как и надо.
             *  недостаток - выглядит ужасно.
             */
 
            if (oki == 1) // для проверки перевожу назад
            {
                i = byteArrayToInt(qba);
                os << i;
            }
            else if (oki == 2)
            {
                f = byteArrayToFloat(qba);
                os << f;
            }
        }
 
        os << endl << endl;
        os.flush();
    }
 
    return a.exec();
}
1. Правильно ли я выбрал для этого QByteArray\QDataStream? Или есть более подходящие\простые варианты для перевода Int/FLoat -> QByteArray -> Int/Float?
2. Почему при вводе "q" программа не завершает свою работу? Ввод прекращается, но программа не закрывается а просто висит открытое окошко (даже если запускать не из среды Qt Creator, а из cmd).
3. Есть более красивый вариант выводить QByteArray в читабельный вид? (то есть 0x00 0x00 0x00 0x0F или 0x0000 0x000F и т.д.). Мой вариант мне кажется каким то уродским, хоть и гибким:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            // Вариант №1
            os << QString(qba.toHex()) << endl;
            /* Выводит "000000ff", недостаток - нет возможности форматирования,
             * например если хочу чтобы выводило 0x00 0x00 0x00 0x0F
             */
 
            s = "";
 
            // Вариант №2
            for (const auto& c : qba)
                s.append(QString("0x%1 ")
                            .arg(QString::number((quint8)c, 16)
                                 .toUpper(), 2, QChar('0')));
 
            os << s << endl;
            /* Выводит "0x00 0x00 0x00 0x0F" как и надо.
             *  недостаток - выглядит ужасно.
             */
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.10.2015, 11:18
Ответы с готовыми решениями:

QMap<int, QVector<float>> копирование QVector<float> в другой вектор
Добрый вечер. У меня есть функция FaceSearchDB. Я хочу копировать значения из vectorа в QMap в...

Преобразование QByteArray в тип float
Задача в следующем. Имеется 4 байта, упакованные в QByteArray. Эти 4 байта содержат в себе число...

QByteArray в int
Привет всем! Ситуация такая: с контроллера через COM передаю unsigned long int ловлю в Qt...

Перевести QByteArray в int
Нужно перевести QByteArray в int такой вариант не подходит: QByteArray bayt; int podschet; ...

11
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
23.10.2015, 14:23 2
Цитата Сообщение от pav1uxa Посмотреть сообщение
1. Правильно ли я выбрал для этого QByteArray\QDataStream? Или есть более подходящие\простые варианты для перевода Int/FLoat -> QByteArray -> Int/Float?
2. Почему при вводе "q" программа не завершает свою работу? Ввод прекращается, но программа не закрывается а просто висит открытое окошко (даже если запускать не из среды Qt Creator, а из cmd).
3. Есть более красивый вариант выводить QByteArray в читабельный вид? (то есть 0x00 0x00 0x00 0x0F или 0x0000 0x000F и т.д.). Мой вариант мне кажется каким то уродским, хоть и гибким:
Я не понимаю основного: int/float и прочие уже находятся в бинарном виде.
Про endian - у Qt есть набор шаблонных функций в QtEndian.

1. QByteArray - это просто массив данных типа char(byte). Отличается от обычного массива только огромным количеством свистелок и перделок, плюс, как и все разумные контейнеры, берёт работу с памятью на себя.
2. Потому что у вас неправильно написана программа. У вас там нужно не просто прекращать работу цикла for, а вызывать функцию quit() у QCoreApplication.
3. У QByteArray есть функция toHex(), которая возвращает массив в виде hex-текста. Массив затем можно преобразовать к QString и вывести на экран.
C++ (Qt)
1
 os << QString(qba.toHex());
P.S. В общем и целом вы абсолютно правы, ваше решение ужасно. Куча велосипедов.
Собственно могу подсказать две вещи - прочитать документация по QByteArray (особенно - обратить внимание на функции, там есть как функции преобразования к типам, так и обратные)
А так же посмотреть пример консольной программы с QCoreApplication.
0
1939 / 1763 / 825
Регистрация: 23.01.2014
Сообщений: 6,211
23.10.2015, 21:18  [ТС] 3
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Я не понимаю основного: int/float и прочие уже находятся в бинарном виде.
Правильно. Но чтобы мне передать пакет который состоит из таких интежеров и флоатов, их сначала надо упаковать в массив байт.
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Про endian - у Qt есть набор шаблонных функций в QtEndian.
Правильно есть. В QDataStream также есть такая фишка, BigEndian там по умолчанию. А QtEndian какая то не универсальная штука. Если в функцию qToBigEndian скормить число, которое и так хранится в BigEndian - оно превратится в littleEndian, например...
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
1. QByteArray - это просто массив данных типа char(byte). Отличается от обычного массива только огромным количеством свистелок и перделок, плюс, как и все разумные контейнеры, берёт работу с памятью на себя.
Правильно.
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
2. Потому что у вас неправильно написана программа. У вас там нужно не просто прекращать работу цикла for, а вызывать функцию quit() у QCoreApplication.
Ну вызвал я функцию quit(). И статически, и у объекта a. Результат тот же, ничего не изменилось.

В общем убрал QCoreApplication вообще, и без него сойдет...

Цитата Сообщение от Shtirliz72 Посмотреть сообщение
3. У QByteArray есть функция toHex(), которая возвращает массив в виде hex-текста. Массив затем можно преобразовать к QString и вывести на экран.
Правильно. И как Вы заметили я указал ее в коде, и указал что именно мне не нравится.
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
Собственно могу подсказать две вещи - прочитать документация по QByteArray (особенно - обратить внимание на функции, там есть как функции преобразования к типам, так и обратные)
Ему нельзя задать BigEndian\LittleEndian при "преобразовании к типам, так и обратные".
Цитата Сообщение от Shtirliz72 Посмотреть сообщение
P.S. В общем и целом вы абсолютно правы, ваше решение ужасно. Куча велосипедов.
В общем и целом спасибо, ни одной полезной фразы...
0
498 / 477 / 77
Регистрация: 29.05.2015
Сообщений: 3,193
23.10.2015, 22:34 4
Цитата Сообщение от pav1uxa Посмотреть сообщение
Правильно. Но чтобы мне передать пакет который состоит из таких интежеров и флоатов, их сначала надо упаковать в массив байт.
С интом легко: нужно посмотреть, какое там число и разбить его на байты (должно быть 4 байта). Сделать это можно операцией "логическое И", по очереди применяя: & 0xFF000000 - старший байт, & 0x00FF0000 - следующий, и так далее.

Флоат - нужно посмотреть, сколько он занимает памяти, и распарсить его так же.

А на втором конце линии собрать из байтов инты и флоаты.
0
44 / 44 / 12
Регистрация: 05.04.2015
Сообщений: 345
24.10.2015, 01:57 5
Обязательно int и float? Можно все во float писать тогда проблема решится несколькими строчками кода
0
1939 / 1763 / 825
Регистрация: 23.01.2014
Сообщений: 6,211
24.10.2015, 09:56  [ТС] 6
Цитата Сообщение от alexu_007 Посмотреть сообщение
& 0xFF000000 - старший байт,
Если сделать 0xFFFFFFFF & 0xFF000000 получится 0xFF000000 вместо 0xFF. Вы забыли про >> 24. Только все равно не понятно к чему все это. Я это лучше Вас понимаю как получается.
Цитата Сообщение от alexu_007 Посмотреть сообщение
Флоат - нужно посмотреть, сколько он занимает памяти, и распарсить его так же.
Логические операции нельзя применять к переменным типа float. Зачем Вы пишите то о чем не имеете понятия?
Цитата Сообщение от kolts Посмотреть сообщение
Обязательно int и float? Можно все во float писать тогда проблема решится несколькими строчками кода
Обязательно.

Опять же, зачем Вы это пишите и к чему я не понимаю... Ни к одному из моих вопросов все вышеуказанное отношения не имеет...
0
44 / 44 / 12
Регистрация: 05.04.2015
Сообщений: 345
24.10.2015, 11:12 7
Ладно
1.) Правильно. По крайней мере в книгах по которым я изучал Qt ничего другого не предложено
2) Надо убрать return a.exec() а просто return 0. Потому что при выходе из цикла (for) продолжается цикл обработки сообщений объекта a.
3.) Не сталкивался
Класс QDataStream сам знает как писать данные и сам знает как читать, только нужно читать в той же последовательности. То есть он сериализует и десериализует данные. У вас же неизвестна последовательность при чтении, поэтому я написал все писать во флоат, а читая уже преобразовать или в инт или оставить во флоате. Возможно я бы писал в XML, может в текстовом виде писал бы(поставил бы разделитель между переменными перед каждой перменной поставил бы букву i или f),возможно в начале у меня был бы расположен массив с очередностью типов данных. QByteArray кстати имеет встроенную возможность сжимать данные.
1
1939 / 1763 / 825
Регистрация: 23.01.2014
Сообщений: 6,211
24.10.2015, 19:25  [ТС] 8
Цитата Сообщение от kolts Посмотреть сообщение
У вас же неизвестна последовательность при чтении
Все там известно. Это оговаривается протоколом обмена. Там прямо пишется - первые 4 байта это число типа integer, означает то-то и то-то, вторые 4 байта float и так далее... тут вопрос лишь в том как правильно и эффективно переводить их из\в байты. В этом моем коде смысл имеют только функции перевода. Все остальное для теста.
0
44 / 44 / 12
Регистрация: 05.04.2015
Сообщений: 345
24.10.2015, 19:49 9
Вот пример из книги. Зная что мы записали,мы это и считываем.
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
QFile file("file.bin");
if(file.open(QIODevice::WriteOnly)) {
QDataStream stream(&file);
stream.setVersion(QDataStream::Qt_4_5);
stream << QPointF(30, 30) << QImage("image.png");
if (stream.status() != QDataStream::Ok) {
qDebug() << "Ошибка записи";
}
}
file.close();
Для чтения этих данных из файла нужно сделать следующее:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
QPointF pt;
QImage img;
QFile
file("file.bin");
if(file.open(QIODevice::ReadOnly)) {
QDataStream stream(&file);
stream.setVersion(QDataStream::Qt_4_5);
stream >> pt >> img;
if (stream.status() != QDataStream::Ok) {
qDebug() << "Ошибка чтения файла";
}
}
file.close();
Тут QPoint, но если он такой тип пишет, то флоаты и инты тем более.
stream.setVersion(QDataStream::Qt_4_5) Надо указать версию потому что формат записи меняется. Хотя по идее у простых типов не меняется. Можно указать последнюю версию. Только в вашем случае вместо файла будет QByteArray. Таким же способом можно записать свой собственный класс переопределив операторы >> и <<.
Сам сейчас хочу организовать обмен между программами, но буду использовать скорей всего XML, так как будет обмен командами.
0
1939 / 1763 / 825
Регистрация: 23.01.2014
Сообщений: 6,211
24.10.2015, 20:17  [ТС] 10
Цитата Сообщение от kolts Посмотреть сообщение
Сам сейчас хочу организовать обмен между программами, но буду использовать скорей всего XML, так как будет обмен командами.
У меня обмен по сети и на большие расстояния и на больших скоростях. XML это слишком расточительно.
0
498 / 477 / 77
Регистрация: 29.05.2015
Сообщений: 3,193
25.10.2015, 20:54 11
C++ (Qt)
1
2
3
4
5
6
7
8
    float xx = 123.456;
 
    quint8 *xb = (unsigned char *) &xx;
 
    ui->label_1->setText(QString::number(xb[0]) + "  " +
                         QString::number(xb[1]) + "  " +
                         QString::number(xb[2]) + "  " +
                         QString::number(xb[3]));
Результат: 121 233 246 66
0
44 / 44 / 12
Регистрация: 05.04.2015
Сообщений: 345
26.10.2015, 02:15 12
Это велосипед
Запись
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
QbyteArray ba;
QDataStream stream(&ba);
stream.setVersion(QDataStream::Qt_4_5);
int int1 = 5;
int int2 = 6;
int int3 = 7;
int int4 = 8;
float float1 = 5.5;
float float2 = 6.5;
float float3 = 7.5;
float float4 = 8.5;
stream << int1<< int2<<int3<<int4<<float1<<float2<<float3<<float4;
 
....... //посылаем bytearray по сети
 
.......//Принимаем
//Чтение
QbyteArray ba;
int int1;
int int2;
int int3;
int int4;
float float1;
float float2;
float float3;
float float4;
QDataStream stream(&ba);
.......
//записываем в поток из устройства ввода вывода 
.....
stream.setVersion(QDataStream::Qt_4_5);
Читаем в переменные
stream >> int1>> int2>>int3>>nt4>>float1>>float2>>float3>>float4;
Здесь не показано как передавать по сети но этого вопроса не было. Еще возможно надо использовать после записи данных в поток функцию flush(), так как данные буферизируются и могут не быть в определенный момент в байтэррэе

Добавлено через 3 часа 20 минут
Попробовал передать по удп. Все работает. Единственное ошибка в конструкторе, потому что писал по памяти. При записи вместо QDataStream stream(&ba) надо поставить QDataStream stream(&ba,QIODevice::ReadWrite) а при чтении без & QDataStream stream(ba); Этот конструктор только для чтения.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.10.2015, 02:15

Преобразовать int в QByteArray
Вообщем необходимо число int преобразовать в массив байтов QByteArray: пока делаю так: int...

Рефакторинг из QByteArray в int и наоборот
Подскажите как можно лучше перевести четыре байта в int, с помощью функций Qt, сейчас я делаю так:...

Запись signed short int в QByteArray
Добрый день! после долгого поиска в тырнетике, я так и не нашла ответ на мой вопрос( хочется...

Ошибка: invalid conversion from 'int' to 'QList<int>::Node*'
ошибка: invalid conversion from 'int' to 'QList&lt;int&gt;::Node*' .h private: QList&lt;int&gt;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru