Russian Qt Forum

Программирование => С/C++ => Тема начата: Edynchik от Февраль 10, 2015, 21:21



Название: двухбайтное число в quint16
Отправлено: Edynchik от Февраль 10, 2015, 21:21
Есть такая ситуация, число лежит в массиве побайтно младшими вперед например 0x020e, т.е.
Код:
buf[0] = 0x0e;buf[1] =0x02;
как сделать так, чтобы записать число в quint16? пробовал
Код:
quint16 n = (quint16)buf[1];
,чтобы явное преобразование захватило сразу два байта, но что то не выходит, прошу помощи.


Название: Re: двухбайтное число в quint16
Отправлено: Old от Февраль 10, 2015, 21:23
Есть такая ситуация, число лежит в массиве побайтно младшими вперед например 0x020e, т.е.
Код:
buf[0] = 0x0e;buf[1] =0x02;
как сделать так, чтобы записать число в quint16? пробовал
Код:
quint16 n = (quint16)buf[1];
,чтобы явное преобразование захватило сразу два байта, но что то не выходит, прошу помощи.
buf[0]


Название: Re: двухбайтное число в quint16
Отправлено: Edynchik от Февраль 10, 2015, 21:24
да и buf[0] пробовал выдает не 2 а 14, что то тоже не то, там вроде указатель должен быть???


Название: Re: двухбайтное число в quint16
Отправлено: kambala от Февраль 10, 2015, 21:35
наверное что-то типа такого должно быть:
Код
C++ (Qt)
quint16 n = *(reinterpret_cast<quint16 *>(buf));


Название: Re: двухбайтное число в quint16
Отправлено: Edynchik от Февраль 10, 2015, 21:51
спасибо, правда сейчас нет под рукой компилятора, завтра проверю.


Название: Re: двухбайтное число в quint16
Отправлено: Пантер от Февраль 10, 2015, 22:19
qFromLittleEndian, qFromBigEndian.


Название: Re: двухбайтное число в quint16
Отправлено: juvf от Февраль 11, 2015, 12:55
наверное что-то типа такого должно быть:
Код
C++ (Qt)
quint16 n = *(reinterpret_cast<quint16 *>(buf));
будет работать до поры до времени, пока адрес buf выровнен. если не проследить за выравниванием, то словите ошибку во время выполнения, причем трудноуловимую. лучше не баловаться подобным приведением типа, а сделать что-то типа

quint16 n = buf[0] + (buf[1] >> 8);


Название: Re: двухбайтное число в quint16
Отправлено: Igors от Февраль 11, 2015, 13:23
наверное что-то типа такого должно быть:
Код
C++ (Qt)
quint16 n = *(reinterpret_cast<quint16 *>(buf));
будет работать до поры до времени, пока адрес buf выровнен. если не проследить за выравниванием, то словите ошибку во время выполнения, причем трудноуловимую. лучше не баловаться подобным приведением типа, а сделать что-то типа

quint16 n = buf[0] + (buf[1] >> 8);
Что за мифическое выравнивание? Давайте проверим
Код
C++ (Qt)
#pragma pack(push, 1)
struct CTest {
char ch;
char buf[128];
};
#pragma pack(pop)
...
CTest test;
quint16 * dst = (quint16 *) &test.buf[0];
*dst = 5;
qDebug() << dst << *dst;
 
Неужели *dst не будет правильно читаться/писаться если стоит по нечетному адресу ?  :)


Название: Re: двухбайтное число в quint16
Отправлено: juvf от Февраль 15, 2015, 13:46
Что за мифическое выравнивание? Давайте проверим
А не везде эти прагмы работают. Например последний случай на UC-8410 = http://www.moxa.com/product/UC-8410.htm (http://UC-8410 = http://www.moxa.com/product/UC-8410.htm), ARM процессор, эти прагмы не работают. Выравнивание 4.

я присал
Цитировать
если не проследить за выравниванием, то словите ошибку во время выполнения
вы же мне привели код, в котором проследили за выравниванием. Во вторых ваш тестовый код не выявит ни чего.

Код:
CTest test;
quint16 * dst = (quint16 *) &test.buf[0];//допустим buf - нечетный алдрес и выравнивание к 4.
*dst = 5; // если buf на нечетном адресе, то тут ловим ошибку... пишется куданить в сторону. допустим записали в адрес buf-1
qDebug() << dst << *dst; //тут опять ловим ошибку.... опять обращение в сторону и читаем не из адреса buf, а из адреса buf-1
вывод в любом случае будет 5

лучше так проверить
Код:
#pragma pack(push, 1)
char buf[128] = {0};
#pragma pack(pop)
...
buf[1] = 0x34;
buf[2] = 0x12;
quint16 *dst = (quint16 *) &buf[1];
cout << "dst = " << *dst << endl;
*dst = 0xABCD;
cout << "buf[1] = " << buf[1] << "\tbuf[2] = " << buf[2] << endl;


Название: Re: двухбайтное число в quint16
Отправлено: Igors от Февраль 15, 2015, 15:34
лучше так проверить
Давайте так (чуть изменил печать)
Код
C++ (Qt)
#pragma pack(push, 1)
char buf[128] = {0};
#pragma pack(pop)
 
buf[1] = 0x34;
buf[2] = 0x12;
quint16 *dst = (quint16 *) &buf[1];
printf("dst = 0x%x\n", (int) *dst);
*dst = 0xABCD;
printf("dst = 0x%x\n", (int) *dst);
 
Вывод
Цитировать
dst = 0x1234
dst = 0xabcd

// если buf на нечетном адресе, то тут ловим ошибку... пишется куданить в сторону. допустим записали в адрес buf-1
С чего Вы это взяли ??? Пишется начиная с того адреса который дали. Просто если он не выровнен, процессор затратит больше времени ("штрафные такты" и все такое) - но никакой ошибки мы не словим


Название: Re: двухбайтное число в quint16
Отправлено: Old от Февраль 15, 2015, 18:34
С чего Вы это взяли ??? Пишется начиная с того адреса который дали. Просто если он не выровнен, процессор затратит больше времени ("штрафные такты" и все такое) - но никакой ошибки мы не словим
Вы ошибаетесь. Точнее пытаетесь судить обо всем по своим знаниям.
А человек выше даже указал процессор, который не умеет читать не выровненные данные.


Название: Re: двухбайтное число в quint16
Отправлено: juvf от Февраль 16, 2015, 09:09
лучше так проверить
Давайте так (чуть изменил печать)
Код
C++ (Qt)
#pragma pack(push, 1)
char buf[128] = {0};
#pragma pack(pop)
 
buf[1] = 0x34;
buf[2] = 0x12;
quint16 *dst = (quint16 *) &buf[1];
printf("dst = 0x%x\n", (int) *dst);
*dst = 0xABCD;
printf("dst = 0x%x\n", (int) *dst);
 
Вывод
Цитировать
dst = 0x1234
dst = 0xabcd

// если buf на нечетном адресе, то тут ловим ошибку... пишется куданить в сторону. допустим записали в адрес buf-1
С чего Вы это взяли ??? Пишется начиная с того адреса который дали. Просто если он не выровнен, процессор затратит больше времени ("штрафные такты" и все такое) - но никакой ошибки мы не словим

А о чем вообще спор? ТС спросил как из байтового массива получить 2-хбайтное? Ему посоветовали
Цитировать
quint16 n = *(reinterpret_cast<quint16 *>(buf));
Видать ТС новичок и плохо разбирается в привидении типа.  Он этот код использует у себя.... и возможно его buf[0] выровнен к 4. Или у него процессор 8-ми битный. Он в своем коде ни когда не словит ошибку.  Я предостерёг, что пользуясь таким кодом нужно следить за выравниванием. В чем я не прав? Ни кто ему не сказал сделай так
Цитировать
#pragma pack(push, 1)
char buf[128] = {0};
#pragma pack(pop)
quint16 n = *(reinterpret_cast<quint16 *>(buf)
Нужно понимать, что на конкретной архитектуре выравнивание может быть 2 или 4. На некоторых архитектурах не работают прагмы. То, что вы проверили на конкретной архитектуре и заработало - это не значит что будет работать везде. На AVR без прагмы всё будет работать.
ТС использует такое приведение типа без прагмы, как посоветовали, код будет работать. ТС усвоит урок. Потом в другом месте сделает также (или использует этот код)... и обратится по невыровненным данным.... выстрелит себе в ногу. "Прозанимается любовью" с этой багой.... и соскочит на жаву. А потом возникают на форумах холивары, что с/с++ гавно.

Вы в своем коде проследили за выравниванием, т.е. вы прагмами изменили выравнивание к 1. Я говорю тоже самое - нужно учитывать выравнивание.

ps
Код:
*dst = 0xABCD;
printf("dst = 0x%x\n", (int) *dst);
я уже говорил, что такой код не дает проверки. если разыменование *dst происходит неправильно, то вы в неправильный адрес запишите 0xABCD, а потом проверяете прочитав также из неправильного адреса.


Название: Re: двухбайтное число в quint16
Отправлено: Igors от Февраль 16, 2015, 13:25
Цитированием не злоупотребляйте плз
ТС использует такое приведение типа без прагмы, как посоветовали, код будет работать. ТС усвоит урок. Потом в другом месте сделает также (или использует этот код)... и обратится по невыровненным данным.... выстрелит себе в ногу. "Прозанимается любовью" с этой багой.... и соскочит на жаву. А потом возникают на форумах холивары, что с/с++ гавно.
Трогательная забота о ТС - но у него своя голова есть :) А захочет на жабу - тем лучше, слабаки не нужны. Еще до PowerPC я работал на Mac, тогда проц motorola не умел писать в нечет - но он выбрасывал исключение "address must be even". Если опять такой появится и возникнет необходимость его поддержки (Вашу ссылку открыть не могу, но гипотетически это возможно)- ну тогда много чего полетит, и много чего придется переписывать. А до этого не стоит шарахаться от мифических угроз, типа "а вот есть такой проц где.. и тогда, тогда... о ужас!!!"  :) Стандарт запрещает писать по невыровненному адресу? Насколько мне известно - нет. Ну и все, а там посмотрим. Заказ на работу с причудливым процом еще надо получить.

Вот куда более реальная проблема: на Вындоуз тип long всегда 4 байта. а вот на Mac он 8 в 64-bit но 4 в 32-bit. Связанные с этим ошибки совсем не редки. Следуя Вашей логике нужно немедленно истребить все long заменив на что-то типа SInt32. Но сделали ли Вы это?  :)


Название: Re: двухбайтное число в quint16
Отправлено: juvf от Февраль 16, 2015, 15:55
Стандарт запрещает писать по невыровненному адресу? Насколько мне известно - нет. Ну и все, а там посмотрим. Заказ на работу с причудливым процом еще надо получить.
Если на конкретной архитектуре выравнивание 4, то с подобным приведением типа вы должны позаботиться о выравнивании. либо вы должны чтобы buf был кратен 4, либо вы должны указать прагмой нужное выравнивание. выравнивание 4 - это не мифический процессор. Вот  http://www.moxa.com/product/UC-8410.htm - вполне не мифическая микроЭВМ с немифическим Intel XScale IXP435 533 MHz processor.


Цитировать
Что за мифическое выравнивание? Давайте проверим
Код

Цитировать
#pragma pack(push, 1)
struct CTest {
 char ch;
 char buf[128];
};
#pragma pack(pop)
...
CTest test;
quint16 * dst = (quint16 *) &test.buf[0];
*dst = 5;
qDebug() << dst << *dst;


Неужели *dst не будет правильно читаться/писаться если стоит по нечетному адресу ?
Смешно както.... "Что за мифическое выравнивание? Давайте проверим" - и тут же приводите проверочный код, в котором вы позаботились о выравнивании. Если это выравнивание мифическое, зачем вы прагмой изменили выравнивание к 1? Ваш проверочный код выровнен к 1. И данные выровнены к 1. Можно спокойно обращаться к адресам кратным 1. Вы проверьте без выравнивания.

Цитировать
шарахаться от мифических угроз, типа "а вот есть такой проц где.. и тогда, тогда... о ужас!!!"
От каких мифических угроз?  На любом процессоре и любой архитектуре, если делаешь привидение типа
Код:
quint16 n = *(reinterpret_cast<quint16 *>(buf));
проследи, чтобы буф был выровнен. если по дефолту выравнивание 4 - смотри чтоб буф был выровнен к 4. Если ваш буф по нечетному адресу, то измени выравнивание к 1 (хотя не везде это сработает). Так или иначе, но программист обязан следить за выравниванием, при подобном приведении типа. В чем я не прав?

С ваших слов, выравнивание это миф и о нем заботиться не нужно. И в качестве доказательства приводите пример с выровненными данными. В чем смысл?


Название: Re: двухбайтное число в quint16
Отправлено: Igors от Февраль 16, 2015, 17:37
От каких мифических угроз?  На любом процессоре и любой архитектуре, если делаешь привидение типа
Код:
quint16 n = *(reinterpret_cast<quint16 *>(buf));
проследи, чтобы буф был выровнен. если по дефолту выравнивание 4 - смотри чтоб буф был выровнен к 4. Если ваш буф по нечетному адресу, то измени выравнивание к 1 (хотя не везде это сработает). Так или иначе, но программист обязан следить за выравниванием, при подобном приведении типа. В чем я не прав?
Возможно Вы имели ввиду нечто типа
Код
C++ (Qt)
struct CTest {
 char ch;
 quint16 val;
};
CTest test;
...
 
quint16 n = *(reinterpret_cast<quint16 *> (&test.ch + 1);
 
Да, это неверно, n будет совсем не test.val, до которого еще 1 байт. Да, если сделаем #pragma pack 1 для CTest - тогда будет верно. С этим никто не спорит, но это совсем не значит что reinterpret_cast что-то "не так приводит" или читается/пишется куда-то "налево". reinterpret_cast четко работает с тем адресом что дали. Напр если это &test.val - то он и будет читаться/писаться, какое бы выравнивание ни стояло.

Если на конкретной архитектуре выравнивание 4, то с подобным приведением типа вы должны позаботиться о выравнивании. либо вы должны чтобы buf был кратен 4, либо вы должны указать прагмой нужное выравнивание. выравнивание 4 - это не мифический процессор. Вот  http://www.moxa.com/product/UC-8410.htm - вполне не мифическая микроЭВМ с немифическим Intel XScale IXP435 533 MHz processor.
Я открыл ссылку, поискал "align" - не нашел. Пожалуйста "ткните носиком".  


Название: Re: двухбайтное число в quint16
Отправлено: Old от Февраль 16, 2015, 18:08
Есть куча армов, которые не могут обращаться по не выравненным адресам. Вместо доступа будет генерироваться прерывание.
Для правильного доступа, нужно что бы оперант в памяти был выравнен на свою длину, т.е. хотим читать 16 битное число из памяти, оно должно быть выравненно на 2 байта, если 32 битное - то на 4. Нет получи прерывание. Конечно можно самому эмулировать чтение через побайтовое, но это лишние такты.
Зная это, компиляторы генерируют правильный код, пока программист не дотягивается до ручного привидения типов, там компилятор становится бессильным и программист должен все контроллировать сам.


Название: Re: двухбайтное число в quint16
Отправлено: Igors от Февраль 16, 2015, 19:06
Да, действительно, juvf прав, есть такие звери. Вот нашел популярное описание
http://www.aleph1.co.uk/chapter-10-arm-structured-alignment-faq (http://www.aleph1.co.uk/chapter-10-arm-structured-alignment-faq)
Причем да, могут и "втихаря" неверно читать/писать. Признаю - был неправ  :)


Название: Re: двухбайтное число в quint16
Отправлено: juvf от Февраль 16, 2015, 19:08
проверил на дэсктопе код
Код:
    char ch[8] = {1,2,3,4,5,6,7,8};
   uint16_t n = *(reinterpret_cast<uint16_t*>(ch + 1));
в результате n = 770, т.е. т = 0x0302, то что доктор прописал. Процессор i7, винда7, 64х. без всяких прагм заработало.

Запустил этот код на девайсе с процессором AT91SAM7S256 (ARM архитектура) - на строке с reinterpret_cast процессор завис. печалька.

Ну да ладно.... SAM7 наверно мифический.... собрал такой код в UC-8410 (процессор Intel XScale IXP435, ARM-архитектура)

Код:
int main()
{
std::cout << "n= " << std::endl;
    char ch[8] = {1,2,3,4,5,6,7,8};
   uint16_t n = *(reinterpret_cast<uint16_t*>(ch + 1));
std::cout << "n = " << (int)n <<std::endl
Запускаю.... смотрю выхлоп
Код:
root@gp1:/home/juvf# ./test2
n=
n = 258
от куда 258? должно быть 0х0302, что есть 770.  ??? .... а 258 - это есть 0х0201. Как так?! Я же указывал адрес ch + 1, и   reinterpret_cast работает строго с указанным адресом...... так так так... пробуем исправить положение прагмой..... а не вышло.... выхлоп такой же... 258 вместо 770.
 



Название: Re: двухбайтное число в quint16
Отправлено: juvf от Февраль 16, 2015, 19:16
Причем да, могут и "втихаря" неверно читать/писать. Признаю - был неправ  :)
Да да да.... Самое печальное, что некоторые именно втихаря. Ладно сам7 сразу завис. А так втихоря уйдет в сторону.... замучаешься искать.  :)


Название: Re: двухбайтное число в quint16
Отправлено: Igors от Февраль 17, 2015, 09:51
Запустил этот код на девайсе с процессором AT91SAM7S256 (ARM архитектура) -
..
... собрал такой код в UC-8410 (процессор Intel XScale IXP435, ARM-архитектура)
У Вас там что, тазик с процессорами ? :)