Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сабуров С.В. - Язык программирования C и C++ - 2006

.pdf
Скачиваний:
312
Добавлен:
13.08.2013
Размер:
1.42 Mб
Скачать

Язык программирования Си

Умножение (*)

Операция умножения указывает на то, что ее оба операнда должны быть умножены.

Деление (/)

Операция деления указывает на то, что ее первый операнд делится на второй. Если две целые величины не делятся нацело, то результат усекается. Деление на 0 дает непредсказуемые результаты.

Остаток от деления (%)

Результатом операции является остаток от деления первого операнда на второй.

Аддитивные операции

Аддитивные операции выполняют сложение (+) и вычитание ( ). Операндами могут быть целые и плавающие величины. В некоторых случаях аддитивные операции могут также выполняться на адресных величинах. На целых и плавающих операндах выполняются обычные арифметические преобразования. Типом результата является тип операндов после преобразования. Преобразования, выполняемые аддитивными операциями, не поддерживают левого и правого переполнения. Информация теряется, если результат аддитивной операции не может быть представлен типом операндов после преобразования.

Сложение (+)

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

67

Язык программирования Си

Вычитание (!)

Операция вычитает второй операнд из первого. Операнды могут быть целого или плавающего типов. Типы первого и второго операндов могут отличаться. Допускается вычитание целого из указателя и вычитание двух указателей.

Когда целая величина вычитается из указателя, то перед выполнением операции производятся те же самые преобразования, что и при сложении целого с указателем. Результатом вычитания является указатель, адресующий память, расположенную на i позиций перед исходным адресом, где i целое, а каждая позиция — это длина типа, адресуемого указателем. Новый указатель адресует тот же самый тип данных, что и исходный указатель.

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

Адресная арифметика

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

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

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

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

68

Язык программирования Си

элементами, расположенными в промежутке между адресами, заданными операндами.

Аддитивные операции между адресной и целой величинами на машинах с сегментной архитектурой (такие как 8086/8088) может быть неправильной в некоторых случаях.

Операции сдвига

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

Обычные арифметические преобразования выполняются. Тип результата — это тип левого операнда после преобразования. При сдвиге влево правые освобождающиеся биты устанавливаются в нуль. При сдвиге вправо метод заполнения освобождающихся левых битов зависит от типа, полученного после преобразования первого операнда. Если тип unsigned, то свободные левые биты устанавливаются в нуль.В противном случае они заполняются копией знакового бита. Результат операции сдвига не определен, если второй операнд отрицательный.

Преобразования, выполняемые операторами сдвига, не поддерживают левого и правого переполнения. Информация теряется, если результат сдвига не может быть представлен типом первого операнда после преобразования.

Операции отношений

Бинарные операции отношений сравнивают первый операнд со вторым и вырабатывают значение 1 (true) и 0 (false). Типом результата является int. Имеются следующие операции отношений.

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

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

69

Язык программирования Си

первого элемента массива меньше чем адрес следующего элемента.

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

Побитовые операции

Побитовые операции выполняют побитовое И (&), включающее ИЛИ (!) и исключающее ИЛИ (^). Операнды побитовых операций должны быть целого типа, но их типы могут быть отличными. Обычные арифметические преобразования выполняются. Тип результата определяется типом операндов после преобразования.

Побитовое И (&)

Побитовое И сравнивает каждый бит своего первого операнда с соответствующим битом второго операнда. Если оба сравниваемых бита единицы, то соответствующий бит результата устанавливается в 1, в противном случае 0.

Побитовое включающее ИЛИ (!)

Побитовое включающее ИЛИ сравнивает каждый бит своего первого операнда с соответствующим битом второго операнда. Если любой из сравниваемых битов равен 1, то соответствующий бит результата устанавливается в 1. В противном случае оба бита равны 0 и соответствующий бит результата устанавливается в 0.

Побитовое исключающее ИЛИ (^)

Побитовое исключающее ИЛИ сравнивает каждый бит своего первого операнда с соответствующим битом второго операнда. Если один из сравниваемых битов равен 0, а второй бит равен 1, то соответствующий бит результата устанавливается в 1; в противном случае соответствующий бит результата устанавливается в 0.

Логические операции

Логические операции выполняют логическое И (&&) и логическое ИЛИ (!!). Операнды логических операций могут быть целого, плавающего или адресного типа. Типы первого и второго операндов могут быть различными. Операнды логических

70

Язык программирования Си

выражений вычисляются слева направо. Если значения первого операнда достаточно, чтобы определить результат операции, то второй операнд не вычисляется.

Логические операции не выполняют стандартные арифметические преобразования. Вместо этого они вычисляют каждый операнд с точки зрения его эквивалентности нулю. Указатель имеет значение 0, если это значение явно установлено путем присваивания или инициализации. Результатом логической операции является 0 или 1. Тип результата есть int.

Логическое И (&&)

Логическая операция И вырабатывает значение 1, если оба операнда имеют ненулевое значение. Если один из операндов равен 0, то результат также равен нулю. Если значение первого операнда равно нулю, то второй операнд не вычисляется.

Логическое ИЛИ (!!)

Логическая операция ИЛИ выполняет над своими операндами операцию включающего ИЛИ. Она вырабатывает значение 0, если оба операнда имеют значение 0; если какой либо из операндов имеет ненулевое значение, то результат операции равен 1.

Если первый операнд имеет ненулевое значение, то второй операнд не вычисляется.

Операция последовательного вычисления

Операция последовательного вычисления (,) вычисляет два своих операнда последовательно слева направо. Результат операции имеет значение и тип второго операнда. Типы операндов не ограничиваются. Преобразования не выполняются.

Условная операция

В Си есть одна тернарная операция — это условная операция ?:. Она имеет следующее синтаксическое представление:

<operand 1>?<operand 2>:<operand 3>

Выражение <operand 1> вычисляется с точки зрения его эквивалентности нулю. Оно может быть целого, плавающего или адресного типа. Если <operand 1> имеет ненулевое значение, то вычисляется <operand 2> и результатом условной операции является значение выражения <operand 2>. Если <operand 1>

71

Язык программирования Си

равен нулю, то вычисляется <operand 3> и результатом является значение выражения <operand 3>. Заметим, что вычисляется один из операндов <operand 2> или <operand 3>, но не оба.

Тип результата зависит от типов второго и третьего операндов следующим образом:

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

2.Второй и третий операнды могут быть одного и того же структурного, совмещения или адресного типа. Тип результата будет тем же самым типом структуры, совмещения или адреса.

3.Один из второго или третьего операндов может быть указателем, а другой константным выражением со значением 0. Типом результата является адресный тип.

Операции присваивания

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

Операциями присваивания являются следующие:

++

Унарный инкремент.

!!

Унарный декремент.

=

Простое присваивание.

*=

Умножение с присваиванием.

/=

Деление с присваиванием.

%=

Остаток от деления с присваиванием.

72

Язык программирования Си

+=

Сложение с присваиванием.

!=

Вычитание с присваиванием.

<<=

Сдвиг влево с присваиванием.

>>=

Сдвиг вправо с присваиванием.

&=

Побитовое И с присваиванием.

|=

Побитовое включающее ИЛИ с присваиванием.

^=

Побитовое исключающее ИЛИ с присваиванием.

При присваивании тип правого операнда преобразуется к типу левого операнда.

Lvalue!выражения

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

Унарные инкремент и декремент

Унарная операция присваивания (++ и ) инкрементирует или декрементирует свой операнд. Операнд должен быть целого, плавающего или адресного типа. В качестве операнда допустимо также Lvalue выражение.Операнды целого или плавающего типа преобразуются путем сложения или вычитания целой 1. Тип результата соответствует типу операнда. Операнд адресного типа инкрементируется или декрементируется размером объекта, который он адресует. Инкрементированный указатель адресует

73

Язык программирования Си

следующий объект, а декрементированный указатель — предыдущий.

Операции инкремента (++) или декремента ( ) могут появляться перед или после своего операнда. Когда операция является префиксом своего операнда, то операнд инкрементируется или декрементируется и его новое значение является результатом вычисления выражения. Когда операция является постфиксом своего операнда, то непосредственным результатом выражения является значение операнда перед его инкрементированием или декрементированием. После этого результат используется в контексте, а операнд инкрементируется или декрементируется.

Простое присваивание

Операция простого присваивания (=) выполняет присваивание. Правый операнд присваивается левому операнду. При присваивании выполняются некоторые правила преобразования.

Составное присваивание

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

<expression 1> += <expression 2>

и может быть понято как:

<expression 1> = <expression 1> + <expression 2>

Однако, выражение составного присваивания не эквивалентно расширенной версии, поскольку в выражении составного присваивания <expression 1> вычисляется только один раз, в то время как в расширенной версии оно вычисляется дважды: в операции сложения и в операции присваивания. Каждая операция составного присваивания выполняет преобразования, которые осуществляются соответствующей бинарной операций, и соответственно ограничивает типы своих операндов. Результатом операции составного присваивания является значение и тип левого операнда.

74

Язык программирования Си

Старшинство и порядок выполнения

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

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

Только операция последовательного вычисления (,) и логические операции И (&&) и ИЛИ (!!) обеспечивают определенный порядок вычисления операндов. Операция последовательного вычисления (,) обеспечивает преобразование своих операндов слева направо. (Заметим, что запятая, разделяющая аргументы в вызове функции, не является операцией последовательного вычисления и не обеспечивает таких гарантий.)

Логические операции также обеспечивают вычисление своих операндов слева направо. Однако логические операции вычисляют минимальное число операндов, необходимое для определения результата выражения. Таким образом, некоторые операнды выражения могут быть не вычислены. Например, в выражении «x && y ++» второй операнд «y ++» вычисляется только тогда, когда x есть true (не нуль). Так что y не инкрементируется, когда x есть false (нуль).

Побочные эффекты

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

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

75

Язык программирования Си

обеспечивает определенный порядок вычислений. Например, побочный эффект имеет место в следующем вызове функции:

add ( i + 1, i = j +2)

Аргументы вызова функции могут быть вычислены в любом порядке. Выражение «i + 1» может быть вычислено перед «i=j+2», или наоборот, с различным результатом в каждом случае.

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

d=0

a=b++=c++=d++;

Значение a непредсказуемо. Значение d (инициализируется нулем), могло быть присвоено c, затем b и затем a, прежде чем любая из переменных была бы инкрементирована. В этом случае a должно было бы быть эквивалентно нулю.

Второй способ вычисления этого выражения начинается вычислением операнда c++=d++. Значение d (инициализированное нулем) присваивается c, а затем d и c инкрементируются. Затем значение c, которое теперь равно 1, присваивается b и b инкрементируется.

Наконец, инкрементированное значение b присваивается a. В этом случае окончательное значение a равно 2.

Так как язык Си не определяет порядок изменения состояний машины (побочных эффектов) при вычислениях, то оба эти метода вычисления корректны и могут быть выполнены. Операторы, которые зависят от частностей порядка вычисления побочных эффектов, выдают непереносимый и неясный код.

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

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

76

Соседние файлы в предмете Программирование на C++