Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Выражения и приведение арифметических типов




Разделители

 

Разделители, или знаки пунктуации, входят в число лексем языка:

[] () {},;: * = #

Квадратные скобки. Для ограничения индексов одно- и многомерных массивов, а также при записи индексированных элементов используются квадратные скобки [ ]. Примеры:

int A[5]; А -одномерный массив из пяти элементов;

int х, е[3][2]; е -двумерный массив (матрица) размером 3x2.

Выражение с индексированными элементами: е[0][0] = х= А[2] = 4; означает, что начальному элементу массива е, переменной х и третьему элементу массива А присваивается значение 4. Так как индексы в массивах всегда начинаются с 0, то элемент А[2] соответствует третьему элементу массива.

Круглые скобки. Назначение круглых скобок ():

1) выделяют выражения-условия (в операторе "если"):

if (х < 0) х = -х;

2) входят как обязательные элементы в определение и описание (в прототип) любой функции, где выделяют соответственно список формальных параметров и список спецификаций параметров:

float F(float x, int k) /* Определение функции*/

{ тело_функции }

float F(float, int); /* Описание функции – ее.прототип */

3) круглые скобки обязательны при определении указателя на функцию:

int (*pfunc)(); /* Определение указателя pfunc на функцию */

4) группируют выражения, изменяя естественную последовательность выполнения операций:

у = (а + b) / с; /*• Изменение приоритета операций */

5) входят как обязательные элементы в операторы циклов:

for (i=0, j=l; i<j; i+=2, j++) тело_цикла;

while (i<j) тело_цикла;

do тело_циклаwhile (k>0);

6) необходимы при явном преобразовании типа. Примеры:

long i = 12L; /* Определение переменной */

float brig; /* Определение переменной */

brig = (float)i; /* Явное приведение типа */

brig получает значение 12L, преобразованное к типу float;

Фигурные скобки. Для обозначения соответственно начала и конца составного оператора или блока используют фигурные скобки {}. Пример использования составного оператора в условном операторе:

if (d > x) { d--; x++; }

Пример блока - тело любой функции:

float absx (float x)

{

return x>0.0?x:-x;

}

Обратите внимание на отсутствие точки с запятой после закрывающейся скобки '}', обозначающей конец составного оператора или блока.

Фигурные скобки используются при инициализации массивов и структур при их определении:

/* Инициализация массива: */

int month [ ] ={ 1, 2, 3, 4, 5, б, 7, 8, 9, 10,11, 12 };

Запятая. Запятая может быть использована в качестве операции, а может применяться как разделитель. В последнем случае она разделяет элементы списков. Во-первых, это спискиначальных значений элементов массивов и компонентов структур при их инициализации (примеры только что даны).

Другой пример списков - списки формальных и фактических параметров и их спецификаций в функциях.

Третье использование запятой как разделителя - в заголовке оператора цикла:

for (x=pl,y=p2,i=2; i<n; z=x+y; x=y, y=z, i++);

Запятая как разделитель используется также в описаниях и определениях объектов (например, переменных) одного типа:

int i, n,-

float x, у, z, pi, p2;

Запятая в качестве операции уже рассматривалась. Следует обратить внимание на необходимость с помощью круглых скобок отделять запятую-операцию от запятой-разделителя. Например, для элементов следующего массива m используется список с тремя начальными значениями:

int i=l, m[ ]={ i, (i=2,i*i), i };

В данном примере запятая в круглых скобках выступает в роли знака операции. Операция присваивания "=" имеет более высокий приоритет, чем операция "запятая". Поэтому вначале i получает значение 2, затем вычисляется произведение i*i, и этот результат служит значением выражения в скобках. Однако значением переменной i остается 2. Значениями m[0], m[1], m[2] будут соответственно 1, 4, 2.

Точка с запятой. Каждый оператор, каждое определение и каждое описание в программе на языке Си завершает точка с запятой ';'. Любое допустимое выражение, за которым следует ';', воспринимается как оператор. Это справедливо и для пустого выражения, т.е. отдельный символ "точка с запятой" считается пустым оператором. Пустой оператор иногда используется как тело цикла. Примеры операторов-выражений:

i++; /* Результат - только изменение Значения переменной i */

F(z,4); /* Результат определяется телом функции с именем F */

Двоеточие. Для отделения метки от помечаемого ею оператора используется двоеточие':':

метка: оператор;

Многоточие. Это три точки '...' без пробелов между ними. Оно используется для обозначения переменного числа параметров у функции при ее определении и описании (при задании ее прототипа). При работе на языке Си программист постоянно использует библиотечные функции со списком параметров переменной длины для форматных ввода и вывода. Их прототипы выглядят следующим образом:

int printf (const char * format,...); int scanf (const char * format,...);

Звездочка Звездочка '*' используется в качестве знака операции умножения и знака операции разыменования (получения доступа через указатель). В описаниях и определениях звездочка означает, что описывается (определяется) указатель на значение использованного в объявлении типа.

Обозначение присваивания. Для обозначения операции присваивания используется символ '='. Кроме того, в определении объекта он используется при его инициализации:

/* инициализация структуры */

struct {char x, int у} А={ 'z', 1918 };

/* инициализация переменной */

int F = 66;

Признак препроцессорных средств. Символ '#' используется для обозначения директив препроцессора. Например:

#include <stdio.h>

#define

 

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

В арифметических выражениях допустимы следующие операции:

+ - сложение;

- - вычитание;

* - умножение;

/ - деление;

% - деление по модулю (т.е. получение остатка от целочисленного деления первого операнда на второй).

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

Примеры выражений с двумя операндами:

а+b 12.3-х 3.14159*Z k/3 16%i

Нужно быть аккуратным, применяя операцию деления ‘/’ к целочисленным операндам. Например, как мы уже упоминали выше, за счет округления результата значением выражения 5/3 будет 1, а соответствует ли это замыслам программиста, зависит от смысла той конкретной конструкции, в которой это выражение используется. Чтобы результат выполнения арифметической операции был вещественным, необходимо, чтобы вещественным был хотя один из операндов. Например, значением выражения 5.0/2 будет 2.5, что соответствует смыслу обычного деления.

Операции *, /, % имеют один ранг (3), операции +, - также один ранг (4), но более низкий. Арифметические операции одного ранга выполняются слева направо. Для изменения порядка выполнения операций обычным образом используются скобки. Например, выражение (d+b)/2.0 позволяет получить среднее арифметическое операндов d и b.

Введены специфические унарные операции ++ (инкремент) и -- (декремент) для изменения на 1 операнда, который в простейшем случае должен быть переменной (леводопустимым значением). Каждая из этих операций может быть префиксной и постфиксной:

• выражение ++m увеличивает на 1 значение m, и это полученное значение используется как значение выражения ++m (префиксная форма);

• выражение --к уменьшает на 1 значение к, и это новое значение используется как значение выражения --к (префиксная форма);

• выражение i++ (постфиксная форма) увеличивает на 1 значение i, однако значением выражения i++ является предыдущее значение i (до его увеличения);

• выражение j-- (постфиксная форма) уменьшает на 1 значение j, однако значением выражения j-- является предыдущее значение j (до его уменьшения).

Например, если n равно 4, то при вычислении выражения n++*2 результат равен 8, а n примет значение 5. При n, равном 4, значением выражения ++n*2 будет 10, а n станет равно 5.

Операнд для операции ++ (и для операции - -) не может быть константой либо произвольным выражением. Записи ++5 или 84++ будут неверными. ++(j+k) также неверная запись.

Внешнюю неоднозначность имеют выражения, в которых знак унарной операции ++ (или --) записан непосредственно рядом со знаком бинарной операции +:

х+++b или z--d

В этих случаях трактовка выражений однозначна и полностью определяется рангами операций (бинарные аддитивные + и - имеют ранг 4; унарные ++ и — имеют ранг 2). Таким образом:

х+++b эквивалентно (х++)+b

z---d эквивалентно (z--)-d

Отношения и логические выражения. Отношение определяется как пара арифметических выражений, соединенных (разделенных) знаком операции отношения. Знаки операций отношения (уже были введены выше):

< меньше, чем; > больше, чем;

<= меньше или равно; >= больше или равно;

== равно;!= не равно.

a-b>6.3

(x-4)*3==12

б<=44

Логический тип в языке Си отсутствует, поэтому принято, что отношение имеет ненулевое значение (обычно 1), если оно истинно, и равно 0, если оно ложно. Таким образом, значением отношения 6<=44 будет 1.

Операции >, >=, <, <= имеют один ранг 6. Операции сравнения на равенство == и! = также имеют одинаковый, но более низкий ранг 7, чем остальные операции отношений. Арифметические операции имеют более высокий ранг, чем операции отношений, поэтому в первом примере для выражения а-b не нужны скобки.

Логических операций в языке Си три:

! - отрицание, т.е. логическое НЕ {ранг 2);

&& - конъюнкция, т.е. логическое И {ранг 11);

|| - дизъюнкция, т.е. логическое ИЛИ {ранг 12).

Они перечислены по убыванию старшинства (ранга). Как правило, логические операции применяются к отношениям. До выполнения логических операций вычисляются значения отношений, входящих в логическое выражение. Например, если а, b, с - переменные, соответствующие длинам сторон треугольника, то для них должно быть истинно, т.е. не равно 0, следующее логическое выражение:

а+b>с && а+с>b && b+с>а

Несколько операций одного ранга выполняются слева направо, причем вычисления прерываются, как только будет определена истинность (или ложность) результата, т.е. если в рассмотренном примере а+b окажется не больше с, то остальные отношения не рассматриваются - результат ложен.

Так как значением отношения является целое (0 или 1), то ничто не противоречит применению логических операций к целочисленным значениям. При этом принято, что любое ненулевое положительное значение воспринимается как истинное, а ложной считается только величина, равная нулю. Значением!5 будет 0, значением 4 && 2 будет 1 и т.д.

Присваивание (выражение и оператор). С имвол "=" в языке Си обозначает бинарную операцию, у которой в выражении должно быть два операнда - левый (обычно переменная) и правый (обычно выражение). Если z - имя переменной, то

z = 2.3 + 5.1

есть выражение со значением 7.4. Одновременно это значение присваивается и переменной z. Только в том случае, когда в конце выражения с операцией присваивания помещен символ ";", это выражение становится оператором присваивания. Таким образом,

z = 2.3 + 5.1;

есть оператор простого присваивания переменной z значения, равного 7.4.

Тип и значение выражения с операцией присваивания определяются значением выражения, помещенного справа от знака '='. Однако этот тип может не совпадать с типом переменной из левой части выражения. В этом случае при определении значения переменной выполняется преобразование (приведение).

Так как выражение справа от знака '=' может содержать, в свою очередь, операцию присваивания, то в одном операторе присваивания можно присвоить значения нескольким переменным, т.е. организовать "множественное" присваивание, например:

c=x=d=4.0+2.4;

Здесь значение 6.4 присваивается переменной d, затем 6.4 как значение выражения с операцией присваивания "d=4.0+2.4" присваивается х и, наконец, 6.4 как значение выражения "x=d" присваивается с. Естественное ограничение - слева от знака '=' в каждой из операций присваивания может быть только леводопустимое выражение (имя переменной).

В языке Си существует целый набор "составных операций присваивания" {ранг 14). Каждая из составных операций присваивания объединяет некоторую бинарную логическую или арифметическую операцию и собственно присваивание. Операция составного присваивания является основой оператора составного присваивания:

имя переменной ор=выражение;

где ор - одна из операций *, /, %, +, -, &, Ù, |, «,». Если рассматривать конструкцию "ор=" как две операции, то вначале выполняется ор, а затем '='. Например,

х*=2; z+=4; i/=x+4*z;

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

Таким образом, первый пример можно рассматривать как обозначение требования "удвоить значение переменной х"; второй пример - "увеличить на 4 значение переменной z"; третий пример - "уменьшить значение переменной i в (x+4*z) раз". Этим операторам эквивалентны такие операторы простого присваивания:

х=х*2; z=z+4; i=i/(x+4*z);

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

a=b/a; x=z%x.

Приведение типов. Рассматривая операцию деления, мы отметили, что при делении двух целых операндов результат получается целым. Например, значением выражения 5/2 будет 2, а не 2.5. Для получения вещественного результата нужно выполнять деление не целых, а вещественных операндов, например, записав 5.0/2.0, получим значение 2.5.

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

int n=5, k=2;

double d;

int m;

d=(double) n/ (double) k;

m=n/k;

В этом фрагменте значением d станет величина 2.5 типа double, а значением переменной m станет целое значение 2.

Операция деления является только одной из бинарных операций. Почти для каждой из них операнды могут иметь разные типы. Однако не всегда программист должен в явном виде указывать преобразования типов. Если у бинарной операции операнды имеют разные типы (а должны в соответствии с синтаксисом выражения иметь один тип), то компилятор выполняет преобразование типов автоматически, т.е. приводит оба операнда к одному типу. Например, для тех же переменных значение выражения d+k будет иметь тип double за счет неявного преобразования, выполняемого автоматически без указания программиста. Рассмотрим правила, по которым такие приведения выполняются.

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

Правила преобразования в языке Си для основных типов определены стандартом языка. Эти стандартные преобразования включают перевод "низших" типов в "высшие".

Среди преобразований типов выделяют:

• преобразования в арифметических выражениях;

• преобразования при присваиваниях;

• преобразования указателей.

Преобразование типов указателей будет рассмотрено в позже. Здесь рассмотрим преобразования типов при арифметических операциях и особенности преобразований типов при присваиваниях.

При преобразовании типов нужно различать преобразования, изменяющие внутреннее представление данных, и преобразования, изменяющие только интерпретацию внутреннего представления. Например, когда данные типа unsigned int переводятся в тип int, менять их внутреннее представление не требуется - изменяется только интерпретация. При преобразовании значений типа float в значение типа int недостаточно изменить только интерпретацию, необходимо изменить длину участка памяти для внутреннего представления и кодировку. При таком преобразовании из float в int возможен выход за диапазон допустимых значений типа int, и реакция на эту ситуацию существенно зависит от конкретной реализации. Именно поэтому для сохранения мобильности программ в них рекомендуется с осторожностью применять преобразование типов.

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

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

2. Если один из операндов имеет тип long double, то второй тоже будет преобразован в long double.

3. Если п. 2 не выполняется и один из операндов есть double, другой приводится к типу double.

4. Если п. 2 - 3 не выполняются и один из операндов имеет тип float, то второй приводится к типу float.

5. Если п. 2 - 4 не выполняются (оба операнда целые) и один операнд unsigned long int, то оба операнда преобразуются к типу unsigned long int.

6. Если п. 2 - 5 не выполняются и один операнд есть long, другой преобразуется к типу long.

7. Если п. 2 - 6 не выполняются и один операнд unsigned, то другой преобразуется к типу unsigned.

8. Если п. 2 - 7 не выполнены, то оба операнда принадлежат типу int.

Используя арифметические выражения, следует учитывать приведенные правила и не попадать в "ловушки" преобразования типов, так как некоторые из них приводят к потерям информации, а другие изменяют интерпретацию битового (внутреннего) представления данных.




Поделиться с друзьями:


Дата добавления: 2014-12-16; Просмотров: 834; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.013 сек.