Правильный способ обратиться к полю не выровненного объекта

105
13 декабря 2019, 00:20

Не могу найти однозначного ответа на следующий вопрос.

Допустим, у меня имеется какая-то структура данных:

struct Data
{
    int id;
    double values[1024]
    // ...
    uint8_t flags;
    // ...
};

И она лежит в буфере в не выровненном состоянии. Мне известно смещение, по которому объект данной структуры лежит в буфере. Я бы хотел считать определенное поле из этого объекта. Например, поле flags.

uint8_t getFlags(uint8_t *_buffer, size_t _offset)
{
    uint8_t *pu = _buffer + _offset;
    // ...
}

1) Проблема в том, что Стандарт C говорит, что неопределенным поведением является даже попытка сохранить в указателе адрес с не правильным выравниванием:

Data *pd = (Data*)pu;// UB

2) Естественно, попытка разыменовать указатель, в котором хранится адрес с неподходящим для целевого типа выравниванием - это неопределенное поведение.

const uint8_t f = pd->flags;// UB

3) Я бы мог попытаться вытащить данные без разыменования:

uint8_t f;
memcpy(&f, pu + offsetof(Data, flags), sizeof(uint8_t));

Но этот способ выглядит подозрительно. Даже в рамках языка C.

В общем, я хочу понять, как правильно выковыривать определенные поля из объектов, которые лежат в буферах в не выровненном состоянии. Это частая задача, особенно при работе с сетью, драйверами и встраиваемыми системами.

Answer 1

Единственный переносимый способ интерпретировать определённый тип данных из потока (буфера) байт, не опасаясь проблем доступа к невыровненным данным - это побайтово (например, с помощью memcpy) скопировать эти данные в место, где нужное выравнивание обеспечивается.

В случае доступа к невыровненным данным в зависимости от используемой архитектуры можно получить либо проседание производительности, либо, так называемую, ошибку шины (Bus error). В общем случае всё это приводит к неопределённому поведению.

Тем не менее при использовании упаковки структур (если компилятор такое поддерживает), ошибок с доступом к невыровненным данным не будет, но сам факт наличия упаковки может привести к проседанию производительности, хотя это безусловно лучше, чем UB.

В сухом остатке: если есть возможность - делайте упаковку, если нет - копируйте побайтово. Степень оверхеда от всего этого надо смотреть на конкретных примерах конкретных же архитектур.

На основании статьи How to Access Safely Unaligned Data.

READ ALSO
Использование proto в Qt

Использование proto в Qt

Задача: подключиться с вебсокету livecoinnet (https://github

115
QMetaProperty::read: Unable to handle unregistered datatype 'QObjectList'

QMetaProperty::read: Unable to handle unregistered datatype 'QObjectList'

Ошибка: QMetaProperty::read: Unable to handle unregistered datatype 'QObjectList' for property 'ViewshedGeoElement_QMLTYPE_43::PointLogLag'

119
Создание объектов класса с++

Создание объектов класса с++

Предположим, существует некоторый класс foo с конструктором по умолчаниюВ main() происходит его создание

125
Не устанавливается Microsoft Visial Studio 2017

Не устанавливается Microsoft Visial Studio 2017

Пытаюсь установить MSVS 2017На этапе установки SDK установщик начинает требовать какие-то пакеты

113