25. Примеры применения побитовых операций
Как уже говорилось, побитовые операции используются для обработки отдельных двоичных разрядов памяти. Для манипулирования отдельным битом необходимо научиться делать следующее:
• определять значение заданного бита;
• устанавливать значение заданного бита в значение 0 или 1;
• инвертировать значение заданного бита.
Это можно сделать так:
unsigned a = 1234; // Целое значение, битами которого мы будем управлять
unsigned short n = 4; // Номер необходимого бита (от 0 до 31)
bool r; // Значение результата (0 или 1)
/* Узнаем, чему равен n-й бит (двоичный разряд) значения a. Результат поместим в переменную r */
r = a & (1U << n);
cout << "Разряд с номером " << n << " равен " << r << endl; // значение 1
/* Установим n-й бит (двоичный разряд) значения a в 0. Результат поместим в переменную а */
a = a & (~ (1U << n));
cout << "Значение а равно " << a << endl; // значение 1218
/* Проверяем */
r = a & (1U << n);
cout << "Разряд с номером " << n << " равен " << r << endl; // значение 0
/* Возвращаем n-й бит (двоичный разряд) значения a в 1. Результат поместим в переменную а */
a = a | (1U << n);
cout << "Значение а равно " << a << endl; // значение 1234
/* Проверяем */
r = a & (1U << n);
cout << "Разряд с номером " << n << " равен " << r << endl; // значение 1
/* Инвертируем n-й бит (двоичный разряд) значения a. Результат поместим в переменную а */
a = a ^ (1U << n);
cout << "Значение а равно " << a << endl; // значение 1218
/* Проверяем */
r = a & (1U << n);
cout << "Разряд с номером " << n << " равен " << r << endl; // значение 0
/* Еще раз инвертируем n-й бит (двоичный разряд) значения a. Результат поместим в переменную а */
a = a ^ (1U << n);
cout << "Значение а равно " << a << endl; // значение 1234
/* Проверяем */
r = a & (1U << n);
cout << "Разряд с номером " << n << " равен " << r << endl; // значение 1
Изменяя значение переменной n в диапазоне от 0 до 31 можно выполнить все эти действия над любым битом переменной a какое бы значение она не содержала.
Таким образом, для того, чтобы узнать, чему равен двоичный разряд с номером n в значении переменной a, мы воспользовались выражением
a & (1U << n).
Иллюстрация вычисления этого выражения:
Номер разряда: 31 30 … 11 10 9 8 7 6 5 4 3 2 1 0
1U: 0 0 … 0 0 0 0 0 0 0 0 0 0 0 1 = 1
1U << n: 0 0 … 0 0 0 0 0 0 0 1 0 0 0 0
Значение a: 0 0 … 0 1 0 0 1 1 0 1 0 0 1 0 = 1234
a & (1U << n): 0 0 … 0 0 0 0 0 0 0 1 0 0 0 0 = 16
Результатом вычисления этого выражения является целое значение не равное 0. Операция присваивания этого значения логической переменной r автоматически преобразует целое значение 16 в логическое значение true (т.е. 1).
Если бы значение a имело бы разряд с номером 4 равным 0, то результатом вычисления этого выражения было бы значение 0. При выполнении операции присваивания это значение было бы преобразовано в логическое значение false (т.е. 0).
Для установки значения разряда с номером n в переменной a в значение 0 используется выражение
a & (~ (1U << n)).
Иллюстрация вычисления этого выражения:
Номер разряда: 31 30 … 11 10 9 8 7 6 5 4 3 2 1 0
1U: 0 0 … 0 0 0 0 0 0 0 0 0 0 0 1 = 1
1U << n: 0 0 … 0 0 0 0 0 0 0 1 0 0 0 0
~ (1U << n): 1 1 … 1 1 1 1 1 1 1 0 1 1 1 1
Значение a: 0 0 … 0 1 0 0 1 1 0 1 0 0 1 0 = 1234
a & (1U << n): 0 0 … 0 1 0 0 1 1 0 0 0 0 1 0 = 1218
Для установки значения разряда с номером n в переменной a в значение 1 используется выражение
a | (1U << n).
Иллюстрация вычисления этого выражения:
Номер разряда: 31 30 … 11 10 9 8 7 6 5 4 3 2 1 0
1U: 0 0 … 0 0 0 0 0 0 0 0 0 0 0 1 = 1
1U << n: 0 0 … 0 0 0 0 0 0 0 1 0 0 0 0
Значение a: 0 0 … 0 1 0 0 1 1 0 0 0 0 1 0 = 1218
a | (1U << n): 0 0 … 0 1 0 0 1 1 0 1 0 0 1 0 = 1234
Для инвертирования значения разряда с номером n в переменной a используется выражение
a ^ (1U << n).
Иллюстрация вычисления этого выражения при a = 1218:
Номер разряда: 31 30 … 11 10 9 8 7 6 5 4 3 2 1 0
1U: 0 0 … 0 0 0 0 0 0 0 0 0 0 0 1 = 1
1U << n: 0 0 … 0 0 0 0 0 0 0 1 0 0 0 0
Значение a: 0 0 … 0 1 0 0 1 1 0 0 0 0 1 0 = 1218
a ^ (1U << n): 0 0 … 0 1 0 0 1 1 0 1 0 0 1 0 = 1234
Но, если a = 1234, то:
Номер разряда: 31 30 … 11 10 9 8 7 6 5 4 3 2 1 0
1U: 0 0 … 0 0 0 0 0 0 0 0 0 0 0 1 = 1
1U << n: 0 0 … 0 0 0 0 0 0 0 1 0 0 0 0
Значение a: 0 0 … 0 1 0 0 1 1 0 1 0 0 1 0 = 1234
a ^ (1U << n): 0 0 … 0 1 0 0 1 1 0 0 0 0 1 0 = 1218
- 2. Структура и основные элементы программы
- 3.Общее понятие типов данных
- 4. Переменные и константы
- 5.Основные типы данных
- 6. Спецификаторы типов данных
- 7. Определение переменных и констант в программе
- 8. Инициализация переменных различных типов
- 9.Целочисленные типы данных
- 10. Вещественные типы данных
- 11. Особенности представления вещественных типов данных
- 12.Логический тип данных
- 13. Символьный тип данных
- 14. Управляющие последовательности
- 15. Операции и выражения
- 16. Операция присваивания, составные операции присваивания
- 17. Понятие l-значения
- 18. Преобразование типов данных
- 19. Арифметические операции
- 20. Операции инкремента и декремента, их разновидности
- 21. Операции отношения
- 22. Логические операции
- 23. Побитовые операции сдвига
- 24. Побитовые логические операции
- 25. Примеры применения побитовых операций
- 26. Условная операция и ее использование
- 27. Определение объема памяти, необходимого для размещения объектов
- 28. Понятие приоритета операций и его влияние на результаты вычислений
- 31.Флаги форматирования потоков ввода-вывода
- 32. Форматирование ввода-вывода с помощью манипуляторов
- 33.Форматирование ввода-вывода с помощью функций потоков ввода-вывода
- 34. Управление шириной поля вывода и выравниванием данных при выводе
- 35. Управление форматом вывода вещественных значений
- 36. Основные понятия структурного программирования
- 37. Базовый набор управляющих структур
- 39.Условная инструкция (if)
- 40. Инструкция множественного выбора (switch)
- 42. Цикл с постусловием (do while)
- 43. Итерационный цикл (for)
- 46. Инструкция перехода goto
- 47. Понятие рекуррентных вычислений, примеры
- 48. Понятие инварианта цикла
- 49. Понятие и определение массива
- 52. Ввод элементов массивов с клавиатуры
- 53. Декларативная и программная инициализация массивов
- 54. Копирование массивов
- 55. Нахождение минимальных и максимальных значений в массивах
- 56. Сдвиг элементов массивов
- 57. Перестановка элементов в массивах
- 58. Поиск данных в массивах
- 59. Сортировка данных в массивах
- 60. Вычисление сумм и произведений элементов массивов
- 61. Представление текстовых строк в виде массива символов
- 62. Ввод-вывод символьных строк
- 63. Определение фактической длины строки
- 64. Копирование символьных строк
- 65. Основные функции обработки строк библиотеки cstring
- 66. Массивы текстовых строк (двумерные массивы символов)
- 67. Указатели Понятие указателя
- Работа с указателями
- 68. Арифметика указателей
- 69. Индексирование указателей
- 70. Ссылки
- 71. Определение функции
- 72. Инструкция return
- 73. Завершение работы функции
- 74. Механизмы передачи данных через параметры функций
- 75. Передача данных по значению
- 76. Передача данных через указатели
- 77. Передача данных по ссылке
- 78. Параметры по умолчанию
- 79. Функции с переменным числом параметров
- 80. Inline функции
- 81. Перегрузка функций
- 82. Рекурсия
- 83. Прототипы функций