1.Описание языка СИ.
1.3.Выражения и присваивания.
Операция простого присваивания используется для замены значения левого операнда, значением правого операнда. При присваивании производится преобразование типа правого операнда к типу левого операнда по правилам, упомянутым раньше. Левый операнд должен быть модифицируемым.
Пример:
int t;
char f;
long z;
t=f+z;
Значение переменной f преобразуется к типу long, вычисляется f+z ,результат преобразуется к типу int и затем присваивается переменной t.
Кроме простого присваивания, имеется целая группа операций присваивания, которые объединяют простое присваивание с одной из бинарных операций. Такие операции называются составными операциями присваивания и имеют вид:
(операнд-1) (бинарная операция) = (операнд-2) .
Составное присваивание по результату эквивалентно следующему простому присваиванию:
(операнд-1) = (операнд-1) (бинарное операция) (операнд-2) .
Отметим, что выражение составного присваивания с точки зрения реализации не эквивалентно простому присваиванию, так как в последнем операнд-1 вычисляется дважды.
Каждая операция составного присваивания выполняет преобразования, которые осуществляются соответствующей бинарной операцией. Левым операндом операций (+=) (-=) может быть указатель, в то время как правый операнд должен быть целым числом.
Примеры:
double arr[4]={ 2.0, 3.3, 5.2, 7.5 } ;
double b=3.0;
b+=arr[2]; /* эквивалентно b=b+arr[2] */
arr[3]/=b+1; /* эквивалентно arr[3]=arr[3]/(b+1) */
Заметим, что при втором присваивании использование составного присваивания дает более заметный выигрыш во времени выполнения, так как левый операнд является индексным выражением.
В языке СИ операции с высшими приоритетами вычисляются первыми. Наивысшим приоритетом является приоритет равный 1. Приоритеты и порядок операций приведены в табл. 8.
Таблица 8
Приоритет |
Знак операции |
Типы операции |
Порядок выполнения |
2 |
() [] . -> |
Выражение |
Слева направо |
1 |
- ~ ! * & ++ -- sizeof приведение типов |
Унарные |
Справа налево |
3 |
* / % |
Мультипликативные |
Слева направо |
4 |
+ - |
Аддитивные |
|
5 |
<< >> |
Сдвиг |
|
6 |
< > <= >= |
Отношение |
|
7 |
== != |
Отношение (равенство) |
|
8 |
& |
Поразрядное И |
|
9 |
^ |
Поразрядное исключающее ИЛИ |
|
10 |
| |
Поразрядное ИЛИ |
|
11 |
&& |
Логическое И |
|
12 |
|| |
Логическое ИЛИ |
|
13 |
? : |
Условная |
|
14 |
= *= /= %= += -= &= |= >>= <<= ^= |
Простое и составное присваивание |
Справа налево |
15 |
, |
Последовательное вычисление |
Слева направо |
Операции присваивания в сложных выражениях могут вызывать побочные эффекты, так как они изменяют значение переменной. Побочный эффект может возникать и при вызове функции, если он содержит прямое или косвенное присваивание (через указатель). Это связано с тем, что аргументы функции могут вычисляться в любом порядке. Например, побочный эффект имеет место в следующем вызове функции:
prog (a,a=k*2);
В зависимости от того, какой аргумент вычисляется первым, в функцию могут быть переданы различные значения.
Порядок вычисления операндов некоторых операций зависит от реализации и поэтому могут возникать разные побочные эффекты, если в одном из операндов используется операции увеличения или уменьшения, а также другие операции присваивания.
Например, выражение i*j+(j++)+(--i) может принимать различные значения при обработке разными компиляторами. Чтобы избежать недоразумений при выполнении побочных эффектов необходимо придерживаться следующих правил.
1. Не использовать операции присваивания переменной в вызове функции, если эта переменная участвует в формировании других аргументов функции.
2. Не использовать операции присваивания переменной в выражении, если эта переменная используется в выражении более одного раза.