Инициализация битовых полей

когда вы пишите

struct {
    unsigned a:3, b:2;
} x = {10, 11};

is x.b гарантированно 3 по ANSI с (С89)? Я читал и перечитывал стандарт, но, похоже, не могу найти именно этот случай.

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

кроме того, (говоря о unsigned t:4) "содержит значения в диапазоне [0,15]", но это не обязательно означает, что инициализатор должен быть уменьшено по модулю 16 для отображения на [0,15].

инициализация структуры действительно кропотливо подробно описана, но я действительно не могу найти именно это поведение. (Конечно, компиляторы делают именно это. И документация IBM говорит : "Когда вы назначаете значение, которое находится вне диапазона для битового поля сохраняется битовый шаблон низкого порядка и назначаются соответствующие биты.- но я хотел бы знать, стандартизирует ли это ANSI C.

2 ответов


WRT "говорит о вычислении, а не об инициализации", стандарт C89 явно применяет правила присвоения и преобразования к инициализации. Он также говорит:

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

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


"ANSI C" / C89 устарел на 25 лет. Поэтому мой ответ ссылается на текущий стандарт C ISO 9899: 2011, также известный как C11.


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

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

подробные правила инициализации структуры, которые вы упомянули (6.7.9), показывают, как литерал 11 в списке инициализаторов связан с переменной b. В этом нет ничего странного. Тогда применяется "простое задание", то же самое, что произошло бы, если бы вы написали x.b = 11;.

при выполнении любого вида назначения или инициализации в C правый операнд преобразовать к типу левого операнда. Это указано в C11 6.5.16:

в простом присваивании ( = ) значение правого операнда преобразуется к типу выражения присваивания и заменяет сохраненное значение в объекте, обозначенном левым операндом.

в вашем случае, буквальный 11 типа int преобразуется в битовое поле unsigned int: 2.

, правило, которое вы ищете, должно быть найдено в главе, посвященной конверсиям (C11 6.3). Применяется то, что вы уже цитировали в своем вопросе, C11 6.3.1.3:

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

максимальное значение unsigned int: 2 это 3. Одно больше максимального значения-3+1=4. Компилятор должен неоднократно вычитать это из значения 11:

11 - (3+1) = 7    does not fit, subtract once more:
 7 - (3+1) = 3    does fit, store value 3

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