Перейти к содержанию
    

*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, либое ещё где уже готовые методы/шаблоны. Или уже кем-то ураденно написано... только нужно знать, где это взять. Кто-нибудь может подсказать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

+1 .

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 для знаковых соотвественно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...