Первоначально переменная 1UL имеет 1 в самом младшем бите и по крайней мере 31 нулевой бит. Она определена как unsigned long, поскольку тип int гарантированно имеет только 16 битов, а необходимо по крайней мере 27. Это выражение сдвигает 1 на 27 битовых позиций, вставляя в биты позади 0.

К этому значению и значению переменной quiz1 применяется оператор OR. Поскольку необходимо изменить значение самой переменной quiz1, используем составной оператор присвоения (см. раздел 4.4):

quiz1 |= 1UL << 27; // указать, что ученик номер 27 сдал контрольную

Оператор |= выполняется аналогично оператору +=.

quiz1 = quiz1 | 1UL << 27; // эквивалент quiz1 |= 1UL << 21;

Предположим, что учитель пересмотрел контрольные и обнаружил, что ученик 27 фактически списал работу. Теперь учитель должен сбросить бит 27 в 0. На сей раз необходимо целое число, бит 27 которого сброшен, а все остальные установлены в 1. Применение побитового AND к этому значению и значению переменной quiz1 позволяет сбросить только данный бит:

quiz1 &= ~(1UL << 27); // ученик номер 27 не прошел контрольную

Мы получаем значение со всеми установленными битами, кроме бита 27, инвертируя предыдущее значение. У него все биты были сброшены в 0, кроме бита 27, который был установлен в 1. Применение побитового NOT к этому значению сбросит бит 27, а все другие установит. Применение побитового AND к этому значению и значению переменной quiz1 оставит неизменными все биты, кроме бита 27.

И наконец, можно узнать, как дела у ученика 27:

bool status = quiz1 & (1UL << 27); // как дела у ученика 27?

Здесь оператор AND применяется к значению с установленным битом 27 и значением переменной quiz1. Результат отличен от нуля (т.е. истинен), если бит 27 в значении переменной quiz1 установлен; в противном случае он нулевой.

Операторы сдвига (они же ввода и вывода) имеют левосторонний порядок

Хотя многие программисты никогда не используют побитовые операторы непосредственно, почти все они использует их перегруженные версии в виде операторов ввода и вывода. Перегруженный оператор имеет тот же приоритет и порядок, что и его встроенная версия. Поэтому программисты должны иметь понятие о приоритете и порядке операторов сдвига, даже если они никогда не используют их встроенные версии.

Поскольку операторы сдвига имеют левосторонний порядок, выражение

cout << "hi" << " there" << endl;

выполняется так:

( (cout << "hi") << " there" ) << endl;

В этом операторе операнд "hi" группируется с первым символом <<. Его результат группируется со вторым, а его результат с третьим символом.

Приоритет операторов сдвига средний: ниже, чем у арифметических операторов, но выше, чем у операторов отношения, присвоения и условных операторов. Эти различия в уровнях приоритета свидетельствуют о том, что для правильной группировки операторов с более низким приоритетом следует использовать круглые скобки.

cout << 42 + 10;   // ok: приоритет + выше, поэтому выводится сумма

cout << (10 < 42); // ok: группировку определяют скобки; выводится 1

cout << 10 < 42;   // ошибка: попытка сравнить cout с 42!

Последний оператор cout интерпретируется так

(cout << 10) < 42;

Он гласит: "записать 10 в поток cout, а затем сравнить результат (т.е. поток cout) со значением 42".

Упражнения раздела 4.8

Упражнение 4.25. Каково значение выражения ~'q' << 6 на машине с 32-битовыми целыми числами и 8-битовыми символами, с учетом, что символ 'q' имеет битовое представление 01110001?

Упражнение 4.26. Что будет, если в приведенном выше примере оценки учеников использовать для переменной quiz1 тип unsigned int?

Упражнение 4.27. Каков результат каждого из этих выражений?

unsigned long ul1 = 3, ul2 = 7;

(a) ul1 & ul2   (b) ul1 | ul2

(c) ul1 && ul2  (d) ul1 || ul2

<p>4.9. Оператор <code>sizeof</code></p>

Оператор sizeof возвращает размер в байтах результата выражения или указанного по имени типа. Оператор имеет правосторонний порядок. Результат оператора sizeof — это константное выражение (см. раздел 2.4.4) типа size_t (см. раздел 3.5.2). Оператор существует в двух формах.

sizeof(тип)

sizeof выражение

Во второй форме оператор sizeof возвращает размер типа, возвращаемого выражением. Оператор sizeof необычен тем, что он не выполняет свой операнд.

Sales_data data, *p;

Перейти на страницу:

Похожие книги