Должен ли я использовать битовые поля для отображения входных последовательных данных? - PullRequest
2 голосов
/ 24 апреля 2019

У нас есть данные, поступающие через последовательный порт (Bluetooth), который отображается на определенную структуру. Некоторые части структуры имеют суббайтовый размер, поэтому «очевидным» решением является сопоставление входящих данных с битовым полем. Что я не могу понять, так это то, повлияет ли на него битовая последовательность машины или компилятора (что сложно проверить), и стоит ли мне вообще отказаться от битовых полей.

Например, у нас есть часть данных размером 1,5 байта, поэтому мы использовали структуру:

{
    uint8_t data1; // lsb
    uint8_t data2:4; // msb
    uint8_t reserved:4;
} Data;

Зарезервированные биты всегда 1

Так, например, если входящие данные равны 0xD2,0xF4, значение равно 0x04D2 или 1234.

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

Мои вопросы:

  • Будет data1 всегда представлять правильное значение, как и ожидалось, независимо от порядкового номера (я предполагаю, что да, и что аппаратный / программный интерфейс всегда должен обрабатывать это правильно для одного целого байта - если отправлено 0xD2, 0xD2 должны быть получены)?

  • Могут ли data2 и reserved быть неправильными, с data2, представляющими старшие 4 бита вместо младших 4 бит?

Если да:

  • Зависит ли порядковый номер бита (как правило) от порядкового номера байта или они могут полностью отличаться?

  • Определяется ли порядок байтов аппаратным обеспечением или компилятором? Кажется, что все системы Linux на Intel одинаковы - верно ли это и для ARM? (Если мы можем сказать, что можем поддерживать все сборки Intel и ARM linux, у нас все должно быть в порядке)

  • Есть ли простой способ определить в компиляторе, как его обойти, и зарезервировать записи битовых полей, если необходимо?

Хотя битовые поля - это самый лучший способ кодирования входных данных с точки зрения кода, я полагаю, мне просто интересно, намного ли безопаснее просто отказаться от них и использовать что-то вроде:

struct {
    uint8_t data1; // lsb (0xFF)
    uint8_t data2; // msb (0x0F) & reserved (0xF0)
} Data;

Data d;

int value = (d.data2 & 0x0F) << 16 + d.data1

Причина, по которой мы не просто сделали это в первую очередь, заключается в том, что количество полей данных меньше 1 байта, а не больше 1, что означает, что обычно с битовым полем нам не нужно делать любая маскировка и смещение, поэтому постобработка проще.

1 Ответ

3 голосов
/ 24 апреля 2019

Следует ли использовать битовые поля для отображения поступающих последовательных данных?

Нет.Битовые поля во многом зависят от реализации, что делает их использование кошмарным.

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

Да, но это потому, что uint8_t - это наименьшая возможная адресуемая единица: байт.Для больших типов данных вам нужно позаботиться о байтовом порядке байтов.

Могут ли данные2 и зарезервированы быть неправильными, с данными2, представляющими старшие 4 бита вместо младших 4 бит?

Да.Они также могут быть на разных байтах.Кроме того, компилятор не должен поддерживать uint8_t для битовых полей, даже если он будет поддерживать тип иначе.

Зависит ли порядковый номер бита (как правило) от порядкового номера байта или они могут отличатьсяполностью?

Наименьший значащий бит всегда будет в младшем значащем байте, но невозможно определить в C , где в байте будет бит.

Операторы сдвига битов дают надежную абстракцию порядка, который достаточно хорош: для типа данных uint8_t (1u << 0) всегда наименее значимый и (1u << 7) старший бит для всех компиляторов и для всех архитектур.

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

Является ли битовая последовательность, определяемаяаппаратное обеспечение или компилятор?

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

Есть ли простой способ определить в компиляторе, какой путь есть, и зарезервировать битовые полязаписи при необходимости?

Не совсем.Это зависит от вашего компилятора, как это сделать, если это вообще возможно.

Хотя битовые поля - это самый лучший способ, с точки зрения кода, для отображения входящих данных, я думаю, мне просто интересноесли гораздо безопаснее просто отказаться от них и использовать что-то вроде:

Определенно отказаться от битовых полей, но я бы также рекомендовал вообще отказаться от структур для этой цели, потому что:

  • Вам необходимо использовать расширения компилятора или ручную работу для обработки порядка байтов.

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

  • Вы не можете иметь переменную ширину или дополнительные поля.

  • Очень просто иметь строгие нарушения псевдонимовесли вы не знаете об этих проблемах.Если вы определяете байтовый массив для фрейма данных и приводите его к указателю на структуру, а затем разыменовываете его, во многих случаях у вас возникают проблемы.

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

...