Jump to content
    

*char to long

Нужно из массива байт получить int, long, float, uint32_t и т.п. Явное приведение типов не всегда и не везде работает из-за "выравнивания".

 

писать китайский код типа

 

uint32_t p = (uint32_t)array[7];

p |= (uint32_t)array[8] << 8;

p |= (uint32_t)array[9] << 16;

p |= (uint32_t)array[10] << 24;

 

надоело, да и нецелесообразно.

Можно сделать шаблон для всех типов, но ездить в Тулу со своим самоваром перетаскивать из проекта в проект свой шаблон.... сами понимаете....

 

Наверняка есть либо в std, либое ещё где уже готовые методы/шаблоны. Или уже кем-то ураденно написано... только нужно знать, где это взять. Кто-нибудь может подсказать?

Share this post


Link to post
Share on other sites

Нужно из массива байт получить int, long, float, uint32_t и т.п. Явное приведение типов не всегда и не везде работает из-за "выравнивания".

А какой компилятор не поддерживает #pragma pack ?

Наверняка есть либо в std, либое ещё где уже готовые методы/шаблоны. Или уже кем-то ураденно написано... только нужно знать, где это взять. Кто-нибудь может подсказать?

Копайте в сторону endianess - оно на это более чем завязано.

Share this post


Link to post
Share on other sites

А union для чего созданы? С ними уж точно проблем с выравниванием быть не должно.

Share this post


Link to post
Share on other sites

Нужно из массива байт получить int, long, float, uint32_t и т.п. Явное приведение типов не всегда и не везде работает из-за "выравнивания".

если с порядком старший/младший расхождений нет, можно использовать memcpy(&p,array+7,sizeof(p));

Share this post


Link to post
Share on other sites

А union для чего созданы? С ними уж точно проблем с выравниванием быть не должно.
юнион для другого созданы, тут они не уместны. пришел по уарту массив байт. где-то в массиве лежат uint32_t, где-то float.... нужно из произвольного адреса получить многобайтовые переменные.

 

Share this post


Link to post
Share on other sites

Вариант описанный novikovfb самый правильный с точки зрения стандарта. При желании можно обернуть в несложный шаблон. Стандартного способа не припомню.

Share this post


Link to post
Share on other sites

Нужно из массива байт получить int, long, float, uint32_t и т.п. Явное приведение типов не всегда и не везде работает из-за "выравнивания".

Какое ещё выравнивание, если у вас массив байт? :rolleyes:

uint32_t p = *(uint32_t*)&array[7];

Share this post


Link to post
Share on other sites

Какое ещё выравнивание, если у вас массив байт? :rolleyes:

uint32_t p = *(uint32_t*)&array[7];

Многие процессоры требуют выравнивания 4-байтовых целых по адресу, кратному 4, 2-байтовых - кратному 2, float и double - 4 и 8 соответственно. Там такое выражение может привести к срабатыванию системного прерывания и вылету из программы. А может не привести (как повезет с адресами).

Share this post


Link to post
Share on other sites

Какое ещё выравнивание, если у вас массив байт? :rolleyes:

uint32_t p = *(uint32_t*)&array[7];

может быть так, что процессор обращается к адресам кратно 4. т.е. из uint32_t p = *(uint32_t*)&array[7]; он сделает uint32_t p = *(uint32_t*)&array[4];

 

Share this post


Link to post
Share on other sites

Сторона, передающая разнородные данные, упаковывает (сериализует) их в байтовый поток сообразно своим установкам - endiannes, align, pack и т. п. Возможно, что округление смещения полей uint32_t до 4-х уже учтено при формировании структуры пакета, и это было бы наиболее грамотным решением. В любом случае, вам должен быть известен алгоритм сериализации.

Вы пишете десериализацию байтового потока обратно в разнородные данные на известном вам процессоре - вам и карты (описание потока) в руки. Если офсеты полей uint32_t кратны 4 - то достаточно приведения типа указателя, если нет - придется городить десериализацию.

В любом случае, универсального решения тут не будет, даже в случае memcpy() можно напороться на разный endiannes и т. д.

Share this post


Link to post
Share on other sites

Сторона, передающая разнородные данные, упаковывает (сериализует) их в байтовый поток сообразно своим установкам строго в соответствии с протоколом передачи данных. Протокол абстрагирован от архитектуры (например Modbus). Мне известен алгоритм упаковки. Думаю memcpy - лучшее решение, только всё таки оберну в шаблон, чтоб сырц был компактнее. Я думал, может уже есть компактное решение.

А про endianess..... - на пк использую QtEndianess<>, для мк пока не было нужды. В интернетах пишут, есть макросы для endianess, нешел в #include < linux/kernel.h >, но это линукс. а в маздае? а в МК? в std нечем перевернуть ((

Share this post


Link to post
Share on other sites

А union для чего созданы? С ними уж точно проблем с выравниванием быть не должно.

+1 .

только юнион надо делать с упаковкой в 1 байт, иначе будет больно

Share this post


Link to post
Share on other sites

А про endianess..... - на пк использую QtEndianess<>, для мк пока не было нужды. В интернетах пишут, есть макросы для endianess, нешел в #include < linux/kernel.h >, но это линукс. а в маздае? а в МК? в std нечем перевернуть ((
Передавайте всегда в сетевом порядке. В передатчике и приёмнике используйте htonl/ntohl, htons/ntohs.

Порядок байтов

Share this post


Link to post
Share on other sites

uint32_t p = (uint32_t)array[7];

p |= (uint32_t)array[8] << 8;

p |= (uint32_t)array[9] << 16;

p |= (uint32_t)array[10] << 24;

 

 

Наверняка есть либо в std, либое ещё где уже готовые методы/шаблоны. Или уже кем-то ураденно написано... только нужно знать, где это взять. Кто-нибудь может подсказать?

 

Это нормальный код для этой задачи.

 

Использовать инлайн функции совершенно нормальная практика для подобных целей, например можете сделать так же как в этом примере https://github.com/threatstack/libldns/blob...s/util.h.in#L81

Использовать набор функций ldns_read_uint32, ldns_read_uint16, ldns_read_uint8 для знаковых соотвественно.

Share this post


Link to post
Share on other sites

Посмотрите файлик modbus-data.c из библиотеки libmodbus.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...