Г. Шилдт - Полный справочник по C++ (1109478), страница 13
Текст из файла (страница 13)
Таблица истинности для оператора исюпочаюшего ИЛИ приведена ниже. Р"Ч о 1 о 1 с( о о 1 1 Р о 1 1 о а?заг дев сиаг 1гогь зяос?еы(уоьб? ( айаг а?и ап = геаб пос(еп(?; У* Считывает символ из порта модема *У гесигп(а?з а 1271; ? Четность обычно задается восьмым битом, который обнуляется в результате выполнения операции И. Вторым операндом этого оператора является байт„в котором все биты от ! до 7 равны 1, а восьмой бит равен О. Выражение с?за127 означает попарнос применение операции И ко всем битам, составляющим значение переменной е?з, и битам числа !27. В результате восьмой бит переменной сзг становится равным О.
Предположим, что в переменная сц содержит символ "А" и бит четности. Быт четности 1 1 0 0 0 0 0 1 1 1 1 1 а 0 1 О О 0 О 0 1 Переменная с?з, содержащая символ "а" ы бит четности 1 1 Двоичное представление числа 127 Побитовый оператор И 0 1 Символ "А" без быта четности Побитовая операция ИЛИ, в отличие от операции И, используется лля установки значения бита. Любой бит, равный ! в каком-либо операнде, присваивает 1 соответствующему биту в результате. Посмотрим, например, чему равно выражение 128 ! 3. 1 0 0 0 О О О 0 Двоичное представление числа 128 0 0 0 О О 1 1 1 Двоичное представление числа 3 ( Побитовый оператор ИЛИ 1 0 0 0 О 1 1 1 Результат Операция исклю гаюшего ИЛИ, обычно сокращенно называегаая ХОК, устанавливает значение бита тогда и только тогда, когда оба сравниваемых бита имекзт разные значения. Например, выражение 127 120 вычисляется следующим образом.
Глава 2. Выражения Как следует из этой таблицы, результат операции исключающего ИЛИ равен истинному значению тогда и только тогда, когда только один из операндов является истинным, в противном случае его значение является ложным. Эти операторы часто применяются при разработке драйверов, например, программ, управляющих работой модема, диска или принтера, поскольку с помощью побитовых операций можно определить значения каждого конкретного бита, например, бита четности. (Вит четности подтверждает, что остальные биты не подвергались изменениям.
Обычно это — старший бит в каждом байте.) С помощью побитового оператора И можно сбросить значение бита, т.е. любой бит, равный нулю в каком-либо операнде, обнуляет значение соответствующего бита в результате. Например, приведенная ниже функция считывает символ из порта модема и обнуляст бит четности. | О 1 1 1 1 1 1 1 Двоичное представление числа 127 О 1 1 1 О О О О двоичное представление числа 120 Побитовый оператор исключаюиего ИЛИ О О О О 1 1 1 1 Результат Таблица 2.7.
Умножение и деление с помощью побитовых сдвигов ычвдлел снег х Даенчное лредсменение Значение х=7; х=х«1; х=х«3 х=х«2 х=х»1 х=х»2 ООООО111 ОСОО111О О111ОООО 11ОООООО О11ООООО ООО11ООО 7 14 112 ) 92 96 24 Примечание. Каждый сдвиг битов влево означает умножение на 2.
После выполнения оператора х«2 часть информации пропадет, поскольку биты выходят за границы числа. Каждый сдвиг битов вправо означает деление на 2. Обратите внимание на то, что последующие деления числа не возвращают потерянные биты. Проиллюстрируем операции побитового сдвига следующеи программои. /* Пример побитового сдвига.
*/ 41пс1цйе <асб1о.)з> 1пс иаьп(уо1<)) цпзьдпеб 1пс 1пе З; /* Сдвиги влево */ йог12=07 2<42 2++) ( Часть 1. Основы языка С++: подмножество С Помните, что результатом работы операторов сравнения и логических операторов всегда являются истинные или лажные значения, в то время как аналогичные побитовые операторы могут порождать любые целые числа. Иными словами, результатом побитовых операций являются любые числа, а не только О или 1, как при использовании логических операторов.
Операторы сдвига битов "»" и "«" смещают все биты влево или вправо на указанное количество разрядов. Общин вид операторов побитового сдвига вправо выглядит следующим образом. значение» количество разрядов Оператор побитового сдвига влево выглядит так. значение «каеичества разрядов Как только сдвигаемые биты достигают края, с противоположного конца появляются нули. (При слвиге вправо в отрицнтельнол~ целом числе признак знака сохраняется.) Помните, что сдвиг не является кольцевым, т.е. если биты исчезаю~ на одном краю числа, они не появятся на другом.
Бипя, вышедшие за прелелы числа, считаются потерянными. Операции побитового сдвига могут быть очень полезны при декодировании информации, поступающей с внешнего устройства, например модема. Кроме того, побитовые операторы сдвига можно использовать для быстрого умножения или деления целых чисел. С помощью сленга вправо можно эффективно поделить число на 2, а с помощью сдвига влево — умножить на 2, как показано в табл. 2.7. 1 =- 1 « 1; /* Сдвиг влево на 1 бит означает умножение на 2*/ ргтпсс("Сдвиг влево тб: Ъб~п", З, 1); /* Сдвиги вправо "/ бог(2-.0; 3<4; 2++) » 1; /* Сдвиг вправо на 1 бит означает деление на 2*/ ргапсб("Сдвиг вправо Ъб: ЪЖп", кетцпп 0; ) Оператор дополнения до единицы "-" инвсртирует каждый бит операнда.
Это значит, что каждая единица станет нулем, и наоборот. Побитовые операторы часто используются в шифровальных программах. Если вам необходимо сделать файл нечитаемым, достаточно проделать над ним несколько побитовых манипуляций. Проще всего инвертировать каждый бит в байтах, как показано ниже. Исходный байт О О 1 О 1 1 0 О После первого отрицания 1 1 0 1 0 0 1 1 после второго отрицания 0 0 1 0 1 1 О 0 Обратите внимание на то, что двойное отрицание всегда приводит к исходному значению. Следовательно, первое дополнение до единицы зашифрует байт, а второе — восстановит ега. Для кодирования символов можно применять функцию, приведенную ниже.
/* Простая тифровальная функция. */ спас епсобе(с)заг с)1) ( геецгп(-с)1)/ /* дополнение дс единицы */ Разумеется, файл, закодированный с помощью функции евсее(еО, очень легко расшифровать! Тернарный оператор Язык С/С++ содержит очень мощный и удобный оператор, заменяющий некоторые операторы вида 1т-епеп-е1ве. Тернарный оператор "т" имеет следующий вил. Вырижение /? Выражение 2: Выражение 3; Оператор "т" выполняется следующим образам: сначала вычисляется Вырижение 1. Если ано истинно, вычисляется Вырижение 2, и его значение становится результатом всего оператора. Если Выражение ! ложно, вычисляется Вырижение 3, и его значение становится результатом оператора. Рассмотрим фрапчент программы.
х = 10; у = х>9 2 100 : 200; Здесь переменной у присваивается значение 100. Если бы значение переменной х было меньше 9, то переменная у стала бы равно 200. Тот же самый код можно записать с памогцью оператора 1д-е1ве. ~ х — 10; Глава 2. Выражения Ъб!хья) у = 100г е1ао у = йссг Более подробно оператор "з"' обсуждается в главе 3, в которой рассматриваются другие условг гыс операторы. Операторы взятия адреса и разыменования Уяпзптель (рош(сг ча!цс) — это переменная, объявлснная особым образом. в которой хранится адрес объекта опрсдслснного типа. Можно выделить три основные области применения указателей в языке С/С+я. Во-первых, с их помощью легко индскси)ювать элема)ггы массивов. Во-вторых, они позволя)от функциям модифицировать свои параметры.
И, в-трстьих, на основе указателей можно создавать связанные списки и другис динамические структуры данных. Подробнее указатели описываются в главе 5, а пока мы изучим лва оператора, позволяющих ими манипулировать. Первый из них — унарный аперапюр взятия пдреса я, возвращающий адрес своего операнда. (Унарным называется оператор, имеющий только один операнд.) Например, оператор $ аг = Ьсооггег помешает в переменную ж адрес переменной сосце.
Этот адрес относится к ячсикс памяти, а которой находится переменная сосце, и никак нс связан с сс значением. Выражснис вссцпе можно перевести как "адрес переменной сосце". Таким образом, оператор присваивания, приведенный выше, означает: "Присвоить переменной вг адрес переменной сосце*'.
Чтобы лучше понять, что при этом происходит, допустим, что переменная сосце расположена в ячейке с адресом 2000, а сс значение равно 100. То~да в прслыдушсм примере переменной пг будет присвоено число 2000. Второй оператор — оператор разымвггпваяия укпзатеяя *, являющийся противоположностью оператора д. Этот >парный оператор возвращает значснис объекта, расположенного по указанному адресу. Например, если переменная га содержит адрес персмснной ссце, то оператор вц= *ю; присвоит значение переменной сосце переменной ц. Теперь значение псрсмснггог! ц будет равно 100, поскольку именно это число записано в ячейка, в которой хранится переменная гк Оператор разымснования указателя м можно перевести как "значение, хранящееся по адресу". Фрагмсггт программы, показанныи выше, чишстся следующим образом: "присвоить псрсмснной ц значснис, хранящееся по адресу ж".
К сожалению, символ оператора разымснования указателя совпадает с символом операции умножения, а символ оператора взятия адреса — с символом оператора побитового И. Эти операторы никак нс связаны друг с другом. Приоритет операторов разымснования указателя * и взятия адреса а выше, чем приоритет любого арифлгстичсского опсратора, за исключением унарного минуса, имсюшсго такой жс приоритет. В объявлении мсжлу имсцсм типа и именем указатсггя ставится символ *. Он сообщает компилятору, что объявляемая переменная является указатслсм на переменную заданного типа. Например, объявление указателя на переменную типа сцак записывается следующим образом: $ с)гак *суй г В оригинале автор использует несколько иную терминологию, называя указателем адрес переменной, а то. что мы называем указателем, — переменной-указатслем.
Как нам кажется, это ис вполне соответствует как нормам литературного языка, так и традициям, установившимся в русскоязычной литературе по программированию. — Прим. рвд. Часть 1, Основы языка С++: подмножество С Обратите внимание на то, что переменная с)г в данном фрагме)гге программы является указателем на переменную типа свах, а нс символьной переменной. Именно в этом заключается нх принципиальное различие. Тип переменной, на которую ссылается указатель (в данном случае тип свах), называется бпзовми шилом указал)егл.