Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
flags = flags ^MASK;
flags ^= MASK;
Например, пусть flags равно 00001111 и MASK — 10110110. Выражение
flags ^MASK становится
(00001111) ^(10110110) // выражение
Манипулирование битами 637
и после вычисления дает следующий результат:
(10111001) // результат
Все биты, установленные в 1 внутри MASK, приводят к переключению соответствующих битов в flags. Все биты в flags, которые соответствуют битам 0 в MASK, остаются неизмененными.
Случай применения: проверка значения бита
Вы уже видели, как изменять значения битов. Предположим, что вместо этого нужно проверить значение какого-нибудь бита. Например, установлен ли в 1 бит 1 в flags? Простое сравнение flags и MASK здесь не подойдет:
if (flags == MASK)
puts("Совпадает !"); /* не работает */
Даже если бит 1 переменной flags установлен в 1, значение какого-то другого бита в flags может сделать результат сравнения недействительным. Чтобы выполнить сравнение только бита 1 в flags с MASK, необходимо сначала замаскировать остальные биты flags:
if ((flags & MASK) == MASK)
puts("Совпадает!");
Побитовые операции имеют приоритет ниже, чем у операции ==, поэтому выражение flags & MASK должно быть заключено в скобки.
Во избежание неполного охвата информации, битовая маска должна иметь ширину не меньше, чем у маскируемого значения.
побитовые операции сдвига
Теперь давайте взглянем на операции сдвига в языке С. Побитовые операции сдвига сдвигают биты влево или вправо. Для большей наглядности мы здесь также будем применять двоичную запись чисел.
Сдвиг влево:<<
Операция сдвига влево (<<) сдвигает биты значения левого операнда влево на количество позиций, заданное правым операндом. Освобождаемые позиции заполняются 0, а биты, выходящие за пределы значения левого операнда, теряются. В следующем примере каждый бит сдвигается на две позиции влево:
(10001010) << 2 // выражение
(00101000) // результат
Эта операция выдает новое битовое значение, но не изменяет операнды. Для примера предположим, что переменная stonk имеет значение 1. Выражение stonk<<2 дает 4, но значением stonk по-прежнему является 1. Чтобы изменить значение переменной, можно воспользоваться операцией сдвига влево с присваиванием (<<=). Эта операция сдвигает биты переменной влево на количество позиций, указанное в правом операнде. Вот пример:
int stonk = 1;
int onkoo;
onkoo = stonk << 2; /* присваивает 4 переменной onkoo */
stonk <<= 2; /* изменяет значение stonk на 4 */
638 Глава 15
Сдвиг вправо:>>
Операция сдвига вправо (>>) сдвигает биты значения левого операнда вправо на количество позиций, указанное в правом операнде. Биты, которые выходят за правую границу левого операнда, теряются. Для типов без знака освобождаемые слева позиции заполняются 0. Для типов со знаком данных результат зависит от системы. Освобождаемые позиции могут заполняться 0 либо битом знака (самого левого):
(10001010) >> 2 // выражение, значение со знаком
(00100010) // результат в одних системах
(10001010) >> 2 // выражение, значение со знаком
(11100010) // результат в других системах
Для значения без знака результат будет следующим:
(10001010) >> 2 // выражение, значение без знака
(00100010) // результат во всех системах
Каждый бит перемещается на две позиции вправо, а освобождаемые позиции заполняются 0.
Операция сдвига вправо с присваиванием (>>=) сдвигает вправо биты левого операнда на заданное в правом операнде количество позиций, например:
int sweet = 16; int ooosw;
ooosw = sweet >> 3; /* ooosw равно 2, sweet по-прежнему 16 */ sweet >>=3; /* значение sweet изменилось на 2 */
Случай применения: побитовые операции сдвига
Побитовые операции сдвига могут служить удобным и эффективным (в зависимости от оборудования) средством выполнения умножения и деления на степени 2:
number << n Умножает number на 2 в степени n
number >> n Делит number на 2 в степени n, если значение number неотрицательно
Эти операции сдвига аналогичны смещению десятичной точки при умножении или делении на 10.
Операции сдвига могут также использоваться для извлечения групп битов из более крупных конструкций. Предположим, что для представления значений цвета применяется переменная типа unsigned long, причем младший байт содержит интенсивность красной составляющей, следующий байт — интенсивность зеленой составляющей, а третий байт — интенсивность синей составляющей цвета. Пусть необходимо сохранить интенсивность каждой составляющей в собственной переменной типа unsigned char. Для этого можно написать такой код:
#define BYTE_MASK 0xff
unsigned long color = 0x002al62f;
unsigned char blue, green, red;
red = color & BYTE_MASK;
green = (color >> 8) & BYTE_MASK;
blue = (color >> 16) & BYTE_MASK;
В коде посредством операции сдвига вправо 8-битовое значение составляющей цвета перемещается в младший байт. Затем с помощью приема с маской значение младшего байга присваивается желаемой переменной.
Манипулирование битами 639
пример программы
В главе 9 при написании программы преобразования чисел в двоичное представление мы использовали рекурсию. Теперь мы решим ту же задачу с применением побитовых операций. Программа в листинге 15.1 читает вводимое с клавиатуры целое число и передает его вместе с адресом строки в функцию по имени itobs(), которая строит для целочисленного значения строку с двоичным представлением. Для определения подходящей комбинации 0 и 1, помещаемой в строку, эта функция использует побитовые операции.
Листинг 15.1. Программа binbi t.с
640 глава 15
В листинге 15.1 применяется макрос CHAR BIT из заголовочного файла limits.h. Этот макрос представляет количество битов в типе char. Операция sizeof возвращает размер в терминах char, поэтому выражение CHAR_BIT * sizeof (int) дает количество битов в значении int. Массив bin_str содержит на один элемент больше этой величины, чтобы можно было добавить в него завершающий нулевой символ.
Функция itobs() возвращает тот же самый адрес, который ей был передан, так что ее вызов можно использовать, к примеру, в качестве аргумента printf(). На первой итерации цикла for функция вычисляет выражение 01 & n. Операнд 01 — это восьмеричное представление маски, у которой все биты кроме нулевого установлены в 0. Следовательно, результатом 01 & n будет значение последнего бита в n. Значением является 0 или 1, но для массива необходим символ ‘0’ или символ ‘1 '. Преобразование осуществляется добавлением кода для '04 (Это предполагает, что цифры кодируются последовательно, как в ASCII.) Результат помещается в предпоследний элемент массива. (Последний элемент зарезервирован для нулевого символа.)
Кстати, вместо выражения 01 & n можно применить и 1 & n. Использование восьмеричного значения 1 вместо десятичного выглядит более стильно. С этой точки зрения вариант 0x1 & n, пожалуй, даже лучше.
Читать дальшеИнтервал:
Закладка: