C++ - [33]

Шрифт
Интервал

Побитовые логические операции

amp; ! ^ ~ »» ««

применяются к целым, то есть к объектам типа char, short, int, long и их unsigned аналогам, результаты тоже цлые.

Одно из стандартных применений побитовых логических опраций – реализация маленького множества (вектор битов). В этом случае каждый бит беззнакового целого представляет один член множества, а число членов ограничено числом битов. Бнарная операция amp; интерпретируется как пересечение, ! как объединение, а ^ как разность. Для наименования членов такого множества можно использовать перечисление. Вот маленький прмер, заимствованный из реализации (не пользовательского итерфейса) «stream.h»:

enum state_value (* _good=0, _eof=1, _fail=2, _bad=4 *); // хорошо, конец файла, ошибка, плохо

Определение _good не является необходимым. Я просто хтел, чтобы состояние, когда все в порядке, имело подходящее имя. Состояние потока можно установить заново следующим обрзом:

cout.state = _good;

Например, так можно проверить, не был ли испорчен поток или допущена операционная ошибка:


if (cout.state amp;(_bad!_fail)) // не good

Еще одни скобки необходимы, поскольку amp; имеет более всокий приоритет, чем !.

Функция, достигающая конца ввода, может сообщать об этом так:

cin.state != _eof;

Операция != используется потому, что поток уже может быть испорчен (то есть, state==_bad), поэтому

cin.state = _eof;

очистило бы этот признак. Различие двух потоков можно находить так:

state_value diff = cin.state^cout.state;

В случае типа stream_state (состояние потока) такая раность не очень нужна, но для других похожих типов она оказвается самой полезной. Например, при сравнении вектора бит, представляющего множество прерываний, которые обрабатываются, с другим, представляющим прерывания, ждущие обработки.

Следует заметить, что использование полей (#2.5.1) в действительности является сокращенной записью сдвига и маскрования для извлечения полей бит из слова. Это, конечно, моно сделать и с помощью побитовых логических операций, Например, извлечь средние 16 бит из 32-битового int можно следующим образом:

unsigned short middle(int a) (* return (a»»8) amp;0xffff; *)

Не путайте побитовые логические операции с логическими операциями:

amp; amp; !! !

Последние возвращают 0 или 1, и они главным образом ипользуются для записи проверки в операторах if, while или for (#3.3.1). Например, !0 (не ноль) есть значение 1, тогда как ~ 0 (дополнение нуля) есть набор битов все-единицы, который обычно является значением -1.

3.2.5 Преобразование типа

Бывает необходимо явно преобразовать значение одного тпа в значение другого. Явное преобразование типа дает значние одного типа для данного значения другого типа. Например:

float r = float(1);

перед присваиванием преобразует целое значение 1 к знчению с плавающей точкой 1.0. Результат преобразования типа не является lvalue, поэтому ему нельзя присваивать (если только тип не является ссылочным типом).

Есть два способа записи явного преобразования типа: трдиционная в C запись приведения к типу (double)a и функцинальная запись double(a). Функциональная запись не может прменяться для типов, которые не имеют простого имени. Например, чтобы преобразовать значение к указательному типу надо или использовать запись преобразования типа

char* p = (char*)0777;


или определить новое имя типа:

typedef char* Pchar; char* p = Pchar(0777);

По моему мнению, функциональная запись в нетривиальных случаях предпочтительна. Рассмотрим два эквивалентных примера

Pname n2 = Pbase(n1-»tp)-»b_name; //функциональная запись Pname n3 = ((Pbase)n2-»tp)-»b_name; // запись приведения // к типу Поскольку операция -» имеет больший приоритет, чем прведение, последнее выражение интерпретируется как

((Pbase)(n2-»tp))-»b_name

С помощью явного преобразования типа к указательным тпам можно симитировать, что объект имеет совершенно проивольный тип. Например:

any_type* p = (any_type*) amp;some_object;

позволит работать посредством p с некоторым объектом some_object как с любым типом any_type.

Когда преобразование типа не необходимо, его следует ибегать. Программы, в которых используется много явных преоразований типов, труднее понимать, чем те, в которых это не делается. Однако такие программы легче понимать, чем программы, просто не использующие типы для представления понятий блее высокого уровня (например, программу, которая оперирует регистром устройства с помощью сдвига и маскирования, вместо того, чтобы определить подходящую struct и оперировать ею, см. #2.5.2). Кроме того, правильность явного преобразования типа часто критическим образом зависит от понимания програмистом того, каким образом объекты различных типов обрабатваются в языке, и очень часто от подробностей реализации. Например:

int i = 1; char* pc = «asdf»; int* pi = amp;i;

i = (int)pc; pc = (char*)i; // остерегайтесь! значение pc может изм//ниться // на некоторых машинах // sizeof(int)«sizeof(char*) pi = (int*)pc; pc = (char*)pi; // остерегайтесь! значение pc может изм// ниться // на некоторых машинах char* // представляется иначе, чем int*

На многих машинах ничего плохого не произойдет, но на других результаты будут катастрофическими. Этот код в лучшем случае непереносим. Обычно можно без риска предполагать, что указатели на различные структуры имеют одинаковое представлние. Кроме того, любой указатель можно (без явного преобразвания типа) присвоить void*, а void* можно явно преобразовать к указателю любого типа.


Еще от автора Мюррей Хилл
Справочное руководство по C++

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


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Пользовательские истории. Искусство гибкой разработки ПО

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


Программное обеспечение и его разработка

Автор книги — американский специалист по программированию, один из руководителей фирмы IBM, в своей книге делает попытку изложить общие проблемы создания программного обеспечения, его сопровождения и использования. Особенно подробно рассматриваются все фазы разработки программ разных типов. Изложение ясное, удачно иллюстрировано примерами.Для программистов разной квалификации и пользователей ЭВМ.fb2: ВНИМАНИЕ. В тексте присутствуют таблицы. Рекомендуется читать файл с помощью программы, поддерживающей их отображение.


Справочник по PHP

Вниманию читателей предлагается справочник по PHP.Справочник предназначается для людей, уже освоивших азы программирования на языке PHP.Справочник создан на основе информации, предоставленной на сайте «Справочник Web-языков» www.spravkaweb.ru.


Симуляция частичной специализации

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


Давайте создадим компилятор!

Эта серия, написанная в период с 1988 по 1995 года и состоящая из шестнадцати частей, является нетехническим введением в конструирование компиляторов. Серия является руководством по теории и практике разработки синтаксических анализаторов и компиляторов языков программирования. До того как вы закончите чтение этой книги, вы раскроете каждый аспект конструирования компиляторов, разработаете новый язык программирования и создадите работающий компилятор.