Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Затем в цикле выполняются операторы i— и n >>= 1. Первый оператор приводит к переходу на предыдущий элемент массива, а второй сдвигает биты в n на одну позицию вправо. На следующей итерации цикла код найдет значение нового самого правого бита. После этого соответствующий ему символ цифры помещается в элемент, предшествующий последней цифре. В подобной манере функция заполняет массив справа налево.
Для отображения результирующей строки можно применять printf() или puts(). Тем не менее, в листинге 15.1 определена функция show_bstr(), которая разбивает последовательность битов на группы по четыре, чтобы облегчить восприятие строки.
Ниже приведен пример выполнения программы:
Вводите целые числа и просматривайте их двоичные представления.
Нечисловой ввод завершает программу.
7
7 представляется как 0000 0000 0000 0000 0000 0000 0000 0111
2013
2013 представляется как 0000 0000 0000 0000 0000 0111 1101 1101
-1
-1 is 1111 1111 1111 1111 1111 1111 1111 1111
32123
32123 представляется как 0000 0000 0000 0000 0111 1101 0111 1011
q
Программа завершена.
Еще один пример
Давайте рассмотрим еще один пример. На этот раз цель заключается в том, чтобы написать функцию, которая инвертирует последние n битов в значении, принимая в качестве аргументов n и само значение.
Операция ~ инвертирует биты, но делает это со всеми битами в байте, а не только с избранными. Однако, как вы уже видели, для переключения отдельных битов можно использовать операцию ^(исключающее “ИЛИ”). Предположим, что создана маска, в которой последние n битов установлены в 1, а остальные — в 0. Тогда применение ^к этой маске и значению переключает, или инвертирует, последние n битов, оставляя остальные биты без изменений. Такой подход реализован в следующем фрагменте кода:
Манипулирование битами 641
int invert_end(int num, int bits)
{
int mask = 0; int bitval = 1;
while (bits-- > 0)
{
mask |= bitval; bitval <<= 1;
}
return num ^mask;
}
Маска создается в цикле while. Изначально в mask все биты установлены в 0. На первой итерации цикла бит 0 устанавливается в 1, после чего значение bitval увеличивается до 2, т.е. в нем бит 0 устанавливается в 0, а бит 1 — в 1. На следующей итерации бит 1 в mask устанавливается в 1 и т.д. В конце концов, операция num ^mask дает желаемый результат.
Для тестирования функции ее можно внедрить в предыдущую программу, как показано в листинге 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. В одних системах поддерживается порядок слева направо, в других - справа налево. Кроме того, системы различаются местоположением границ между полями. По этим причинам битовые поля не особенно переносимы. Однако обычно они применяются в целях, не предполагающих переносимость, таких как размещение данных в точной форме, используемой отдельным аппаратным устройством.
Пример с битовыми полями
Битовые поля часто применяются в качестве более компактного способа хранения данных. Предположим, что вы решили представить свойства выводимого на экран окна. Давайте отложим в сторону все сложности графики и предположим, что окно обладает только перечисленными ниже свойствами.
• Окно может быть прозрачным или непрозрачным.
Читать дальшеИнтервал:
Закладка: