Безопасное присвоение значений битовому полю в C

Предположим, у меня есть

typedef struct {
    unsigned short bar   :    1;
} foo_bf;

typedef union {
  unsigned short val;
  foo_bf bf;
} foo_t;

Как мне правильно присвоить значение этому битовому полю из типа, например, uint16_t?

uint16_t myValue = 1;
foo_t foo;
foo.bf.bar = myValue 

При запуске PC-Lint возникает ошибка MISRA: Выражение назначено более узкому или другому основному типу.

Я безуспешно пытался ограничить количество используемых битов.

foo.bf.bar = (myValue 0x1U)

Есть ли шанс сделать его совместимым с MISRA, если мне придется использовать значение uint16_t в качестве источника?


person MergeMaster    schedule 21.09.2018    source источник
comment
Превратить myValue в _Bool? Если это не сработает, возможно, вам придется жить с предупреждением.   -  person Shawn    schedule 21.09.2018
comment
if (myValue) myFoo.bar = 1; else myFoo.bar = 0; при условии, что foo_bf myFoo, и мусор foo_t   -  person user3386109    schedule 21.09.2018
comment
в зависимости от того, к какому более узкому типу относится ошибка, может быть достаточно foo.bf.bar = (unsigned short) myValue;   -  person Sander De Dycker    schedule 21.09.2018


Ответы (2)


Модель основных типов MISRA-C на самом деле не применима к битовым полям. Термины «уже» и «шире» относятся к размеру в байтах (см. 8.10.2). Таким образом, не очевидно, должен ли статический анализатор предупреждать здесь или нет, поскольку правила для основных типов не относятся к битовым полям.
EDIT: Здесь я был неправ, см. ответ Андрея. Приложение D.4 рассказывает, как преобразовать тип битового поля в соответствующую категорию основного типа.

Однако использование битовых полей в приложении MISRA-C — плохая идея. Битовые поля очень плохо определены стандартом и, следовательно, недетерминированы и ненадежны. Кроме того, MISRA-C 6.1 требует, чтобы вы документировали, как ваш компилятор поддерживает битовые поля с uint16_t, поскольку это не один из стандартных целочисленных типов, разрешенных для битовых полей.

Но настоящим препятствием здесь является Директива 1.1, которая требует документирования и понимания всего поведения, определяемого реализацией. Для реализации MISRA-C я однажды попытался задокументировать все аспекты битовых полей, определяемые реализацией. Вскоре я поймал себя на том, что пишу целое эссе, потому что с ними столько проблем. см. это для вершины айсберга .

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

person Lundin    schedule 21.09.2018
comment
Учитывая, что здесь требуется только один флаг (хорошо, может быть, это просто пример), подойдет unsigned char без какой-либо логики битового поля. - person Antti Haapala; 21.09.2018
comment
Недетерминированный кажется немного сильным. Я бы ожидал поведения отдельной версии компилятора для конкретной платформы - это то, что вы обычно документируете, да? - быть последовательным (для любого компилятора, достойного сертификации). Неужели это так плохо документировать? - person Leushenko; 21.09.2018
comment
@Leushenko Выравнивание единицы хранения не просто определяется реализацией, оно не указано. Это означает, что один и тот же компилятор время от времени может делать это по-разному, и ему не нужно документировать, когда и как. Так что да, с точки зрения программиста, битовые поля имеют недетерминированное поведение, как только они используются как нечто иное, чем кусок логических флагов, где порядок распределения или отображение памяти не имеет значения. С точки зрения компилятора (внутренней) они детерминированы. - person Lundin; 21.09.2018

Приложение D.4 MISRA C:2012 удобно озаглавлено «Основные типы битовых полей».

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

Беззнаковый тип самого низкого ранга однобитового целого числа без знака будет uint8_t (он же unsigned char) — при условии, что инструмент не интерпретирует однобитовый как логический...

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

foo.bf.bar = (uint8_t)myValue

Кроме того, MISRA C: 2012 Правило 6.1 дает рекомендации по использованию типов, отличных от signed/unsigned int, для битовых полей...

person Andrew    schedule 24.09.2018
comment
Я не знал об этой части в этом Приложении, поэтому кажется, что часть моего собственного ответа неверна в отношении основного типа (исправим). Однако что такое подписанный тип? Стандарт C, по-видимому, не указывает, является ли int : n логическим, подписанным или беззнаковым типом. И как статический анализатор должен знать поведение конкретной цели, определяемое реализацией? MISRA-C должен просто полностью запретить битовые поля: они никогда не должны быть разрешены в критических системах. - person Lundin; 24.09.2018
comment
Кстати, слышали ли вы когда-нибудь о бедолаге, который задокументировал все аспекты битовых полей, определяемые реализацией? В соответствии с требованиями Директивы 1.1. Если MISRA настаивает на разрешении битовых полей, возможно, им также следует опубликовать примечание/книгу по применению, содержащую все определяемое реализацией поведение битовых полей, чтобы каждому разработчику MISRA-C не приходилось писать такую ​​книгу. - person Lundin; 24.09.2018
comment
Рад передать предложение команде... конечно, было бы лучше, если бы WG14 исправила это в стандарте, но мы знаем, что этого никогда не произойдет :( - person Andrew; 25.09.2018
comment
Битовые поля представляют собой заметную опасность, особенно во встроенных системах, поскольку в настоящее время с каждой цепочкой инструментов появляется карта регистров микроконтроллера, загроможденная битовыми полями. И действительно, если бы WG14 действительно исправила стандарт, MISRA-C был бы не нужен :) - person Lundin; 25.09.2018