Для иллюстрации некоторых побитовых операций рассмотрим функцию getbits(x, p, n), которая формирует поле в n битов, вырезанных из x, начиная с позиции p, прижимая его к правому краю. Предполагается, что 0-й бит - крайний правый бит, а n и p - осмысленные положительные числа. Например, getbits(x,4,3) вернет в качестве результата 4, 3 и 2-й биты значения x, прижимая их к правому краю. Вот эта функция:
>/* getbits: получает n бит, начиная с p-й позиции */
>unsigned getbits(unsigned x, int p, int n)
>{
> return (x ›› (p+1-n)) & ~(~0 ‹‹ n);
>}
Выражение x ›› (р+1-n) сдвигает нужное нам поле к правому краю. Константа ~0 состоит из одних единиц, и ее сдвиг влево на n бит (~0 ‹‹ n) приведет к тому, что правый край этой константы займут n нулевых разрядов. Еще одна операция побитовой инверсии ~ позволяет получить справа n единиц.
Упражнение 2.6. Напишите функцию setbits(x, p, n, y), возвращающую значение x, в котором n битов, начиная с p-й позиции, заменены на n правых разрядов из y (остальные биты не изменяются).
Упражнение 2.7. Напишите функцию invert(x, p, n), возвращающую значение x с инвертированными n битами, начиная с позиции p (остальные биты не изменяются).
Упражнение 2.8. Напишите функцию rightrot (x, n), которая циклически сдвигает x вправо на n разрядов.
2.10 Операторы и выражения присваивания
Выражение
>i = i + 2;
в котором стоящая слева переменная повторяется и справа, можно написать в сжатом виде:
>i += 2;
Оператор +=, как и =, называется оператором присваивания.
Большинству бинарных операторов (аналогичных + и имеющих левый и правый операнды) соответствуют операторы присваивания op=, где op - один из операторов
>+
>-
>*
>/
>%
>‹‹
>››
>&
>^
>|
Если выр>1 и выр>2 - выражения, то
>выр>1 op= выр>2
Эквивалентно
>выр>1 = (выр>1) op (выр>2)
с той лишь разницей, что выр>1 вычисляется только один раз. Обратите внимание на скобки вокруг выр>2:
>x *= y + 1
эквивалентно
>x = x * (y + 1)
но не
>x=x*y+1
В качестве примера приведем функцию bitcount, подсчитывающую число единичных битов в своем аргументе целочисленного типа.
>/* bitcount: подсчет единиц в х */
>int bitcount(unsigned х)
>{
> int b;
> for (b = 0; х != 0; x ››= 1)
> if (x & 01)
> b++;
> return b;
>}
Независимо от машины, на которой будет работать эта программа, объявление аргумента x как unsigned гарантирует, что при правом сдвиге освобождающиеся биты будут заполняться нулями, а не знаковым битом.
Помимо краткости операторы присваивания обладают тем преимуществом, что они более соответствуют тому, как человек мыслит. Мы говорим "прибавить 2 к i" или "увеличить i на 2", а не "взять i, добавить 2 и затем вернуть результат в i", так что выражение i+=2 лучше, чем i=i+2. Кроме того, в сложных выражениях вроде