ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4236
Скачиваний: 28
Часть I. Язык программирования С
46
Если выражение содержит несколько операторов, которые имеют
одинаковый приоритет, то порядок вычисления этих операторов
не определен.
Для того чтобы задать порядок вычисления операторов, в выра-
жении используются круглые скобки. Операторы, заключенные в
круглые скобки со своими операндами, вычисляются до операто-
ров, которые находятся вне этих круглых скобок. Например, в
следующем выражении оператор
+
вычисляется до оператора
*
.
int x = 1, y =2, z;
z = (x + y) * y; /* z = 6 */
При программировании выражений лучше расставлять скобки,
это значительно упрощает понимание выражения.
Если в выражении нет круглых скобок, то порядок вычисления
нескольких подряд идущих одинаковых операторов определяется
ассоциативностью операторов
. Унарные операторы вычисляют-
ся справа налево, а бинарные наоборот — слева направо. Напри-
мер, выражение:
x + y + z,
эквивалентно выражению:
(x + y) + z
.
Кроме того, при разборе выражения компилятор распознает лек-
семы наибольшей длины. Например, выражение:
y = ++x;
,
интерпретируется как:
y = (++x);
,
а не как:
y = +(+x);
.
Принимая во внимание, что символы ++ обозначают оператор
инкремента, который будет рассмотрен далее.
Глава 3. Операторы и выражения
47
3.7. Приведение типов
в выражениях
Приведением типов
называется преобразование значения одного
типа к значению другого типа, при этом возможно как сохране-
ние величины этого значения, так и изменение этой величины.
Часто приведение типов также называют
преобразованием типов
.
Если в выражении встречаются переменные и константы разных
типов, то все они приводятся к типу с наибольшим диапазоном
значений. Такое приведение типов называется
неявным
. Перечис-
лим типы по убыванию их диапазонов значений:
long double
double
float
unsigned long
long
unsigned int
int
Как видим, в этой иерархии отсутствуют типы, диапазон значе-
ний которых не превышает диапазон значений типа
int
. Причина
этого заключается в том, что если выражение содержит операнды
только интегральных типов, диапазон которых не превышает
диапазон типа
int
, то перед вычислением это выражение всегда
преобразуется компилятором в эквивалентное выражение, все
операнды которого имеют тип
int
. Это делается для того, чтобы
повысить скорость работы программы.
Приведение типов внутри интегрального типа данных называется
интегральным расширением
(integral promotion).
Приведение типов внутри плавающего типа данных называется
расширением с плавающей точкой
(float-point promotion).
Можно сказать, что интегральным расширением и расширением
с плавающей точкой являются такие приведения типов внутри
интегрального и плавающего типов соответственно, при которых
не теряется числовое значение данных приводимого типа.
Часть I. Язык программирования С
48
Стиль программирования на языке C поощряет неявное преобра-
зование типов данных. Ниже приведен пример неявного преобра-
зования типа в выражении:
int x = 1;
double y = 1.5, z;
z = x + y; /* тип переменной x приводится к типу double */
В заключение этого раздела отметим, что неявное преобразова-
ние типов данных в выражениях определяет полиморфизм встро-
енных операторов, который называется
принудительным поли-
морфизмом
(coercion polymorphism).
3.8. Оператор преобразования типов
Для явного преобразования типа выражения используется
опера-
тор преобразования типа
, который имеет вид:
(тип)выражение
Этот оператор приводит значение
выражения
к типу, который ука-
зан в круглых скобках. Например, следующее выражение приво-
дится к типу
int
:
(int)(1.5 / 0.3)
А в следующем выражении к типу
int
приводится только числи-
тель, а тип всего выражения равен
double
:
(int)1.5 / 0.3
Заметим, что приоритет оператора преобразования типа ниже
приоритета унарных операторов, но выше приоритета бинарных
мультипликативных арифметических операторов. Результатом
оператора преобразования типа является R-value.
В языке программирования С++ результат оператора преобразо-
вания типа может дать в результате L-value, если тип, к которому
приводится выражение, является ссылкой.
Учитывая замечание, в языке программирования С++ можно на-
писать следующее выражение:
Глава 3. Операторы и выражения
49
char* p;
(int&)p = 10;
Оператор преобразования типа позволяет выполнить любое пре-
образование арифметических типов данных. С помощью этого
оператора также возможно преобразовать любой тип данных в
тип данных
void
. Однако при помощи этого оператора нельзя
преобразовать тип
void
ни в какой другой тип данных.
3.9. Оператор присваивания
Оператор присваивания
обозначается символом
=
и имеет сле-
дующий вид:
операнд_1 = операнд_2;
В результате выполнения оператора присваивания
операнду_1
присваивается значение
операнда_2
. При этом
операнд_1
должен
быть модифицируемым L-value, а
операнд_2
представлять R-value.
В связи с этим фактом часто полагают, что L-value является крат-
ким обозначением для left value т. е. значение, которое может ис-
пользоваться слева от оператора присваивания, а R_value —
кратким обозначением для right value, т. е. значение, которое мо-
жет использоваться только справа от оператора присваивания.
Это не совсем корректно, но такая трактовка наглядно показывает,
что собой представляют L
-
и R
-
value
.
Результатом оператора присваивания является R-value, значение
которого равно значению
операнда_2
. Приоритет оператора при-
сваивания ниже приоритета всех бинарных операторов. Поэтому
операнд_2
в операторе присваивания может быть выражением.
При присваивании допускаются разные типы операндов. В этом
случае полученное значение выражения, которое находится спра-
ва от оператора присваивания, неявно приводится к типу пере-
менной, которая находится слева от оператора присваивания. До-
пускаются любые преобразования между арифметическими ти-
пами данных. Но если диапазон типа левого операнда меньше
диапазона типа значения выражения, то компилятор может вы-
дать предупреждение. Например:
Часть I. Язык программирования С
50
int x = 1;
double d;
d = x + 2; /* d = 3.0 */
Но в этих случаях нужно быть внимательным, т. к. возможны
ошибки следующего типа:
int x = 1;
double d;
d = x / 2; /* d = 0 */
В последнем примере не учитывается, что выражение сначала
вычисляется, а потом преобразуется к типу левого операнда опе-
ратора присваивания. Чтобы избежать этой ошибки, нужно ис-
пользовать плавающий тип в выражении справа от оператора
равно. Например:
int x = 1;
double d;
d = x / 2.0; /* d = 0.5 */
Так как оператор присваивания возвращает R-value, то возможно
последовательное использование операторов присваивания. На-
пример, в языке программирования C возможна запись следую-
щего выражения:
int x, y, z;
x = y = z = 1; /* x = 1, y = 1, z =1 */
Оно эквивалентно выражению:
x = (y = (z = 1)); /* x=1, y = 1, z =1 */
То есть последовательные операторы присваивания вычисляются
справа налево.
В языке программирования С++ оператор присваивания возвра-
щает L-value.
Учитывая это замечание, в языке программирования можно на-
писать следующее выражение:
int n;
++(n = 10); // n = 11