Для тестирования функции ее можно внедрить в предыдущую программу, как показано в листинге 15.2.
Листинг 15.2. Программа invert4.с

642 глава 15

Ниже представлен пример выполнения программы:
Вводите целые числа и просматривайте их двоичные представления.
Нечисловой ввод завершает программу.
7
7 представляется как 0000 0000 0000 0000 0000 0000 0000 0111 Инвертирование последних 4 битов дает 0000 0000 0000 0000 0000 0000 0000 1000 12541
12541 представляется как 0000 0000 0000 0000 0011 0000 1111 1101 Инвертирование последних 4 битов дает 0000 0000 0000 0000 0011 0000 1111 0010
q
Bye !
Битовые поля
Второй метод манипулирования битами предусматривает использование битового поля, которое представляет собой просто набор соседствующих битов внугри значения типа signed int или unsigned int. (Стандарты С99 и С11 дополнительно разрешают иметь битовые поля типа _Bool.) Битовое поле создается путем объявления структуры, в которой помечено каждое поле и определен его размер. Например, следующее объявление устанавливает четыре однобитовых поля:
struct {
unsigned int autfd : 1; unsigned int bldfc : 1; unsigned int undln : 1; unsigned int itals : 1;
} prnt;
Манипулирование битами 643
Такое определение приводит к получению структуры prnt, содержащей четыре однобитовых поля. Теперь для присваивания значений отдельным полям можно применять обычную операцию членства в структуре:
prnt.itals = 0;
prnt.undln = 1;
Поскольку каждое из этих полей — это просто один бит, присваивать можно только значения 1 и 0. Переменная prnt хранится в ячейке памяти размером типа int, но в этом примере используются только четыре бита.
Структуры с битовыми полями служат удобным средством для отслеживания настроек. Многие настройки, такие как полужирное или курсивное начертание шрифта, сводятся к указанию одной из двух опций: “включено” или “отключено”, “да” или “нет”, “истинно” или “ложно”. Когда нужен одиночный бит, не имеет смысла применять целую переменную. Структура с битовыми полями позволяет хранить множество настроек в одной конструкции.
Временами настройка предусматривает более двух опций, поэтому для представления всех вариантов одного бита оказывается недостаточно. Это не проблема, т.к. размеры нолей не ограничены одним битом. Структуру можно определить следующим образом:
struct {
unsigned int codel : 2; unsigned int code2 : 2; unsigned int code3 : 8;
} prcode;
Этот код создает два 2-битовых поля и одно 8-битовое. Теперь возможны следующие присваивания:
prcode.codel = 0;
prcode.code2 = 3;
prcode.code3 = 102;
Нужно просто следить, чтобы значение не превышало размерность поля.
А что, если общее количество объявленных битов превысит размер типа unsigned int? Тогда будет использоваться следующая область для хранения unsigned int. Отдельное поле не должно перекрывать границу между двумя смежными областями unsigned int. Компилятор автоматически сдвигает такое перекрывающее определение поля, чтобы выровнять его по границе unsigned int. Когда это происходит, в первой области unsigned int остается неименованный промежуток.
Структуру полей можно заполнить неименованными промежутками с применением ширин неименованных полей. Использование неименованного поля шириной О приводит к тому, что следующее поле выравнивается по следующей области целочисленного значения:
struct {
unsigned int fieldl : 1; unsigned int : 2;
unsigned int field2 : 1; unsigned int : 0;
unsigned int field3 : 1; } stuff;
Здесь между полями stuff .heldl и stuff. field2 имеется 2-битовый промежуток, а поле stuff. field3 хранится в следующей области int.
644 глава 15
Важной зависимостью от системы является порядок, в котором поля помещаются в область int. В одних системах поддерживается порядок слева направо, в других - справа налево. Кроме того, системы различаются местоположением границ между полями. По этим причинам битовые поля не особенно переносимы. Однако обычно они применяются в целях, не предполагающих переносимость, таких как размещение данных в точной форме, используемой отдельным аппаратным устройством.
Пример с битовыми полями
Битовые поля часто применяются в качестве более компактного способа хранения данных. Предположим, что вы решили представить свойства выводимого на экран окна. Давайте отложим в сторону все сложности графики и предположим, что окно обладает только перечисленными ниже свойствами.
• Окно может быть прозрачным или непрозрачным.
Читать дальше