Алгоритмизации
Скачать 1.15 Mb.
|
ГЛАВА 4. Обзор операцийОперации,выраженияВыражения используются для вычисления значений (определенного типа) и состоят из операндов, операций и скобок. Каждый операнд может быть, в свою очередь, выражением или одним из его частных случаев– константой или переменной. Операнды задают данные для вычислений. Знак операции – это один или более символов, определяющих действие над операндами, т.е. операции задают действия, которые необходимо выполнить. Внутри знака операции пробелы не допускаются. Операции делятся на унарные, бинарные и тернарные – по количеству участвующих в них операндов, и выполняются в соответствии с приоритетами. Для изменения порядка выполнения операций используются круглые скобки. Большинство операций выполняются слева направо, например, a+b+c→ → (a+b)+c. Исключение составляют унарные операции, операции присваивания и условная операция (?:), которые выполняются справа налево. В языке Си используются четыре унарные операции, имеющие самый высокий приоритет, их часто называют первичными: операция доступа к полям структур и объединений при помощи идентификаторов «.» – точка; операция доступа к полям структур и объединений при помощи указателей «–>» – стрелка; операция [ ] индексации, используемая при декларации массива и обращении к его элементам; операция ( ) обращения к функции. Первичные операции будут рассмотрены в соответствующих разделах. Полный список операций с указанием их приоритетов приводится в прил. 2. АрифметическиеоперацииОбозначения арифметических операций: + (сложение); – (вычитание); / (деление, для int операндов – с отбрасыванием остатка); * (умножение); % (остаток от деления целочисленных операндов со знаком первого операнда– деление «по модулю»). Операндами традиционных арифметических операций (+ – * /) могут быть константы, переменные, обращения к возвращающим значения функциям, элементы массивов, любые арифметические выражения, указатели (с ограничениями). Порядок выполнения действий в арифметических выражениях следующий: выражения в круглых скобках; операции *, /, %; операции +, –. Унарные операции «знак числа» (+, –) обладают самым высоким приоритетом и определены для операндов числовых типов (имеющих числовой результат), при этом «+» носит только информационный характер, «–» меняет знак операнда на противоположный (неадресная операция). Операции *, /, % обладают высшим приоритетом над операциями +, –, поэтому при записи сложных выражений нужно использовать общепринятые математические правила: x круглые скобки. a y�z+−↔ x+y*z–a/(b+с) , т.е. использовать b+ ОперацияприсваиванияФормат операции присваивания: Операнд_1 = Операнд_2 ; Операндом_1 (левый операнд) может быть только переменная. Левый операнд операции присваивания получил название L–значение, (L–value, Left–value) – адресное выражение. Так в Си называют любое выражение, адресующее некоторый участок оперативной памяти, в который можно записать некоторое значение. Переменная – это частный случай адресного выражения. Операндом_2 (правый операнд) могут быть: константа, переменная или любое выражение, составленное в соответствии с синтаксисом языка Си. Правый операнд операции присваивания назвали R–значение, (R–value, Right–value). Присваивание значения в языке Cи, в отличие от традиционной интерпретации, рассматривается как выражение, имеющее значение левого операнда после присваивания. Таким образом, присваивание может включать несколько операций присваивания, изменяя значения нескольких операндов, например: int i, j, k; floatx, y, z; ... i= j = k= 0; ↔ k= 0, j= k, i = j; x= i+ (y= 3) – (z = 0); ↔ z= 0, y= 3, x= i+ y– z; Примерынедопустимыхвыражений:присваивание константе: 2 = x+ y; присваивание функции: getch() = i; присваивание результату операции: (i+ 1) = 2 + y; СокращеннаязаписьоперацииприсваиванияВ языке Си используются два вида сокращенной записи операции присваивания: вместо записи: v= v# e; где # – любая арифметическая операция (операция над битовым представлением операндов), рекомендуется использовать запись v#= e; Например, i= i+ 2; ↔ i+= 2; (знакиопераций–безпробелов); вместо записи: x= x# 1; где #– символы, обозначающие операцию инкремента (+1), либо декремента (–1), x– целочисленная переменная (или переменная-указатель), рекомендуется использовать запись: ##x; – префиксную, или x##; – постфиксную. Если эти операции используются в чистом виде, то различий между постфиксной и префиксной формами нет. Если же они используются в выражении, то в префиксной форме(##x) сначала значение xизменится на 1, а затем полученный результат будет использован в выражении; в постфиксной форме (x##) – сначала значение переменнойхиспользуется в выражении, а затем изменится на 1. Операции над указателями будут рассмотрены в разд. 9.4. Пример1: Пример2:inti, j, k; Смысл записи intn, a, b, c, d; Значения floatx, y; ... n= 2; a= b= c= 0; a= ++n; n=3, a=3 х*= y; x= x*y; a+= 2; a=5 i+= 2; i= i+ 2; b = n++; b=3, n=4 x/= y+15; x= x/(y+ 15); b–= 2; --k; k = k – 1; c = --n; n=3, c=3 k--; k = k – 1; c *= 2; c=6 j = i++; j = i; i= i+ 1; d= n--; j= ++i; i= i+ 1; j= i; d%= 2; b=1 d=3, n=2 d=1 ПреобразованиетиповоперандоварифметическихоперацийЕсли операнды арифметических операндов имеют один тип, то и результат операции будет иметь такой же тип. Но, как правило, в операциях участвуют операнды различных типов. В этом случае они преобразуются к общему типу в порядке увеличения их «размера памяти», т.е. объема памяти, необходимого для хранения их значений. Поэтому неявные преобразования всегда идут от «меньших» объектов к «большим». Схема выполнения преобразований операндов арифметических операций выглядит следующим образом: short, char→ int→ unsigned→ long→ double float→ doubleСтрелки отмечают преобразования даже однотипных операндов перед выполнением операции. То есть действуют следующие правила: значения типов charи shortвсегда преобразуются в int; если один из операндов имеет тип double, то и другой преобразуется в double; если один из операндов long, то другой преобразуется в long. Внимание. Результатом операции 1/3 будет значение 0, чтобы избежать такого рода ошибок, необходимо явно изменить тип хотя бы одного операнда, т.е. записать, например: 1./3 . Типы char и int могут свободно смешиваться в арифметических выражениях. Каждая переменная типа charавтоматически преобразуется в int, что обеспечивает значительную гибкость при проведении преобразований, т.к. над типом intдействия выполняются быстрее, чем над любым другим типом. При выполнении операции присваивания значение правого операнда преобразуется к типу левого, который и является типом полученного результата. И здесь необходимо быть внимательным, т.к. при некорректном использовании операций присваивания могут возникнуть неконтролируемые ошибки. Так, при преобразовании int в char старший байт просто отбрасывается. Пусть: float x; int i; тогда и x = i; и i= x; приводят к преобразованиям, причем float преобразуется в int отбрасыванием дробной части. Тип doubleпреобразуется в floatокруглением. Длинное целое преобразуется в более короткое целое иchar посредством отбрасывания бит в старших разрядах. Итак, безопасным преобразованием типов является преобразование в порядке увеличения «размера памяти», обратное преобразование может привести к потере значащих разрядов. ОперацияприведениятипаВ любом выражении преобразование типов может быть осуществлено явно, для этого достаточно перед выражением поставить в круглых скобках атрибут соответствующего типа: (тип) выражение; ее результат – значение выражения, преобразованное к заданному типу. Операция приведения типа вынуждает компилятор выполнить указанное преобразование, но ответственность за последствия возлагается на программиста. Использовать эту операцию рекомендуется везде, где это необходимо, например: doublex; intn= 6, k= 4; x= (n + k)/3; → x= 3, т.к. дробная часть будет отброшена; x = (double)(n + k)/3; → x= 3.333333 – использование операции приведения типа позволило избежать округления результата деления целочисленных операндов. ОперациисравненияВ языке Си используются следующие операции сравнения, т.е. отношения между объектами:
Пары символов соответствующих операций разделять нельзя. Общий вид операций отношений: Операнд_1 ЗнакоперацииОперанд_2Указанные операции выполняют сравнение значений первого операнда со вторым. Операндами могут быть любые арифметические выражения и указатели. Значения арифметических выражений перед сравнением вычисляются и преобразуются к одному типу. Арифметические операнды преобразуются по правилам, аналогичным для арифметических операций. Операнды-указатели преобразуются в целые числа необходимого типа. Результат сравнения указателей будет корректным в арифметическом смысле лишь для объектов одного массива. В языке Си нет логического типа данных. Результат операции отношения имеет значение 1, если отношение истинно, или в результате вычислений получено не нулевое значение, воспринимаемое компилятором Си как истина (true), или 0 – в противном случае, т.е. – ложно (false). Следовательно, операция отношения может использоваться в любых арифметических выражениях. Операции сравнения на равенство и неравенство имеют меньший приоритет, чем остальные операции отношений. Примеры использования операций отношений: y> 0 , x== y, x!= 2 . Отношения между объектами сложных типов проверяются либо посре- дством последовательного сравнения их элементов (для массивов), либо используя стандартные библиотечные функции, которые будут рассмотрены позже. Логические операцииПриведем логические операции в порядке убывания относительного приоритета. Их обозначения: ! – отрицание (логическое «НЕТ»); && – конъюнкция (логическое «И»); || – дизъюнкция (логическое «ИЛИ»). Операндами (выражениями) логических операций могут быть любые скалярные типы. Ненулевое значение операнда трактуется как «истина», а нулевое – «ложь». Результатом логической операции, как и в случае операций отношения, может быть 1 или 0. Общий вид операции отрицания ! выражениеПримеры использования операции отрицания: !0 → 1 !5 → 0 x= 10; ! (x> 0) → 0 Общий вид операций конъюнкциии дизъюнкции: Выражение_1 знакоперацииВыражение_2 Особенность операций конъюнкции и дизъюнкции – экономное последовательное вычисление выражений-операндов: если выражение_1 операции «конъюнкция» ложно, то результат операции – ноль и выражение_2 не вычисляется; если выражение_1 операции «дизъюнкция» истинно, то результат операции – единица и выражение_2 не вычисляется. Например: y> 0 && x= 7 → истина, если оба выражения истинны; e> 0 || x= 7 → истина, если хотя бы одно выражение истинно. Старшинство операции «И» выше, чем «ИЛИ» и обе они младше операций отношения и равенства. Относительный приоритет логических операций позволяет пользовать- ся общепринятым математическим стилем записи сложных логических выражений, например: 0 < x< 100 ↔ 0 < x&& x< 100 ; x> 0,y≤1 ↔ x> 0 && y<=1 . Учет этих свойств очень существенен для написания правильно работающих программ. Побитовыелогическиеоперации,операциинадбитамиВ языке Си предусмотрен набор операций для работы с отдельными битами. Эти операции нельзя применять к переменным вещественного типа. Обозначения операций над битами: – дополнение (унарная операция); инвертирование (одноместная операция); & – побитовое «И» – конъюнкция; | – побитовое включающее «ИЛИ» – дизъюнкция; ^ – побитовое исключающее «ИЛИ» – сложение по модулю 2; >> – сдвиг вправо; << – сдвиг влево. Общий вид операции инвертирования (поразрядное отрицание): выражениеинвертирует каждый разряд в двоичном представлении своего операнда. Остальные операции над битами имеют вид: Выражение_1 знакоперацииВыражение_2 Операндами операций над битами могут быть только выражения, приводимые к целому типу. Операции(, &, |, ^) выполняются поразрядно над всеми битами операндов (знаковый разряд особо не выделяется): 0xF0 ↔ x0F 0xFF & 0x0F ↔ x0F 0xF0 | 0x11 ↔ xF1 0xF4 ^ 0xF5 ↔ x01 Операция & часто используется для маскирования некоторого множества бит. Например, операторw= n& 0177 передает в wсемь младших бит n, полагая остальные равными нулю. Операции сдвига выполняются также для всех разрядов с потерей выходящих за границы бит. Операция (|) используется для включения бит w = x | y, устанавливает в единицу те биты в x, которые равны 1 в y. Необходимо отличать побитовые операции& и| от логических операций && и || , если x = 1, y = 2, то x & y равно нулю, а x&& yравно 1. 0x81 << 1 ↔ 0x02 0x81 >> 1 ↔ 0x40 Если выражение_1 имеет тип unsigned, то при сдвиге вправо освобо- ждающиеся разряды гарантированно заполняются нулями (логический сдвиг). Выражения типа signedмогут, но необязательно, сдвигаться вправо с копированием знакового разряда (арифметический сдвиг). При сдвиге влево освобождающиеся разряды всегда заполняются нулями. Если выражение_2 отрицательно либо больше длины выражения_1 в битах, то результат операции сдвига не определен. Унарная операция () дает дополнение к целому, т.е. каждый бит со значением 1 получает значение 0 и наоборот. Операции сдвига << и >> применяются к целочисленным операндам и осуществляют соответственно сдвиг вправо (влево) своего левого операнда на число позиций, задаваемых правым операндом, например, x<< 2 сдвигает x влево на две позиции, заполняя освобождающиеся биты нулями (эквивалентно умножению на 4). Операции сдвига вправо на kразрядов весьма эффективны для деления, а сдвиг влево – для умножения целых чисел на 2 в степени k: x<< 1 ↔ x*2; x>> 1 ↔ x/2 ; x<< 3 ↔ x*8 . Подобное применение операций сдвига безопасно для беззнаковых и положительных значений выражения_1. Операции сдвига не учитывают переполнение и потерю значимости. В математическом смысле операнды логических операций над битами можно рассматривать как отображение некоторых множеств с размерностью не более разрядности операнда на значения {0,1}. Пусть единица означает обладание элемента множества некоторым свойством, тогда очевидна теоретико-множественная интерпретация рассма- триваемых операций: – дополнение; | – объединение; & – пересечение. Простейшее применение– проверка нечетности целого числа: int i; ... if ( i & 1) printf (" Значениеi четно!"); Комбинирование операций над битами с арифметическими операциями часто позволяет упростить выражения. Операция«,»(запятая)Данная операция используется при организации строго гарантированной последовательности вычисления выражений (обычно используется там, где по синтаксису допустима только одна операция, а необходимо разместить две и более, например, в операторе for). Форма записи: выражение_1, …, выражение_N; выражения1, 2,…, Nвычисляются последовательно друг за другом и результатом операции становится значение последнего выражения N, например: m= ( i= 1, j= i++, k = 6, n= i+ j+ k); получим последовательность вычислений: i =1, j = i =1, i = 2, k= 6, n= 2+1+6, и в результате m = n= 9. В заключение отметим следующую особенность языка Си – любые операции допускаются только со скалярными объектами, причем небольшого размера, порядка размера регистров процессора. Это объясняется ориента- цией языка на задачи системного программирования. Любые действия с составными или сложными объектами – массивами, строками, структурами и т.п. реализуются с помощью стандартных библиотечных функций, работа с которыми будет рассмотрена позже. |