Операции, выражения и операторы
Понятие выражения, как и понятие переменной, заимствовано из алгебры. Выражение - это группа символов, представляющее некоторое значение. Оно может содержать числа, символы для математических действий, такие как сложение или деление, и даже имена переменных. Например, выражение
(4 х 5) - 4 представляет значение 16.
Почленная интерпретация этого выражения - "взять число 4, умножить его на 5, из результата вычесть 4".
В языке С существует три типа выражений:
- математическое выражение, дающее численный результат;
- текстовое выражение, дающее строку символов;
- логическое выражение, дающее в результате 1 или 0 (интерпретируемые как "истина" или "ложь".
В зависимости от количества операндов различают унарные (один операнд), бинарные (два операнда) и тренарные (три операнда).
Унарные операции:
Операция | Описание | Пример |
& | Получение адреса операнда | int MyVal = 1024; int *pint; pint = &MyVal; *pint = *pint + 1; cout << MyVal; |
* | Обращение по адресу к значению (разыменование) | |
- | Унарный минус – изменение знака арифметического операнда | Изменение знака арифметического операнда |
+ | Унарный плюс | Введен для симметрии с унарным минусом |
~ | Поразрядное инвертирование внутреннего двоичного кода | unsigned short i; (0 ... 65 535); i=10; i=~i; cout << i; |
! | Логическое отрицание значения операнда | |
++ | Инкремент (префиксный или постфиксный) | |
-- | Декремент (префиксный или постфиксный) | |
sizeof | Вычисление размера в байтах | |
:: | Операция доступа |
Бинарные операции:
Операция | Описание операции |
Арифметические операции | |
+ | Сложение |
- | Вычитание |
* | Умножение |
/ | Деление |
% | Получение остатка от деления целочисленных операндов |
Операции отношения (сравнения) | |
< | Меньше |
> | Больше |
<= | Меньше или равно |
>= | Больше или равно |
= = | Равно |
!= | Не равно |
Логические бинарные операции | |
&& | Конъюнкция (И) |
| | | Дизъюнкция (ИЛИ) |
Операции присваивания | |
= | Простое присваивание |
*= | Присваивание произведения значений операндов |
/= | Присваивание частного от деления значений операндов |
%= | Присваивание остатка от деления значений операндов |
+= | Присваивание суммы значений операндов |
-= | Присваивание разности значений операндов |
Операции сдвига | |
<< | Левый сдвиг |
>> | Правый сдвиг |
Поразрядные операции | |
& | Поразрядная конъюнкция битовых представлений значений целочисленных операндов |
| | Поразрядная дизъюнкция -//- |
^ | Поразрядная исключающая дизъюнкция -//- |
Деление целых чисел дает в результате целое число. Дробная часть результата, если она есть, отбрасывается:
int MyVal1 = 21 / 6;
int MyVal2 = 21 / 7;
И MyVal1, и MyVal2 в итоге получат значение 3.
Один нюанс, который вы должны запомнить.
Float res;
res = 5/4;
Результат: res = 1.
Для того, чтобы посчитать "правильно", этот фрагмент программы должен быть
Float res;
res = 5./4.;
Результат: res = 1.25.
Результат получения остатка от деления целочисленных операндов положителен, если оба операнда положительны. Если же один или оба операнда отрицательны, результат зависит от реализации, то есть машинно-зависим.
Значением операции сдвига является битовое представление левого операнда, сдвинутое влево (<<) или вправо (>>) на количество разрядов, равное значению правого операнда.
При левом сдвиге на i разрядов первые i разрядов левого операнда теряются, последние i разрядов левого операнда заполняются нулями.
При правом сдвиге на i разрядов первые i разрядов левого операнда заполняются нулями, если левый операнд имеет беззнаковый тип или имеет неотрицательное значение, в противном случае значение определяется реализацией. Последние i разрядов левого операнда теряются.
Преобразование типов
Преобразование типов при присваивании.
Преобразование типов предназначено для ситуации, в которой переменные одного типа смешиваются с переменными другого типа. Когда возникает подобная ситуация в выражении присваивания, используется правило преобразования типов: значение операнда справа от операции присваивания преобразуется к типу операнда, стоящего слева. Это демонстрируется следующим примером:
int x;
char ch;
float f;
void func(void)
{
ch = x; /* 1 */
x = f; /* 2 */
f = ch; /* 3 */
f = x; /* 4 */
}
В строке 1 левые (старшие) биты целочисленной переменной x обрубаются, оставляя в ch младшие 8 битов. Если х содержит число между 255 и 0, то ch и хбудут иметь одинаковое значение. Иначе значение ch будет содержать только младший набор битов переменной х. В строке 2 х получает целую часть переменной f. В строке 3 f получает 8-битное целое число, хранящееся в ch, преобразованное к формату с плавающей точкой. В строке 4 f получает значение целочисленной переменной х, преобразованное к формату с плавающей точкой.
Когда происходит преобразование из переменной, занимающей большее количество байт в переменную с меньшим, то старшие биты будут потеряны.
Следует помнить два важных момента, которые могут повлиять на переносимость создаваемого кода:
1) Когда происходит преобразование из переменной, занимающей большее количество байт в переменную с меньшим, то старшие биты будут потеряны
2) Преобразование из int в float или из float в double и тому подобное не добавляет точности. Такого рода преобразования только изменяют формат представления значения.
Преобразование типов в выражениях. Когда операнды различных типов смешиваются в выражениях, то происходит преобразование к одному типу. Компилятор преобразует все операнды «вверх», к типу большего операнда. Ниже описываются правила преобразования типов.
1) Все переменные типа char и short int преобразуются к типу int. Все переменные типа float – к типу double.
2) Если один из пары операндов имеет тип long double, другой операнд также преобразуется к long double.
3) Если один из пары операндов имеет тип double, другой операнд (кроме long double) также преобразуется к типу double.
4) Если один из операндов имеет тип long, другой операнд также преобразуется к long.
5) Если один из операндов имеет тип unsigned, другой операнд также преобразуется к типу unsigned.
В результате применения этих правил преобразования каждая пара операндов будет иметь тип и результат каждой операции будет совпадать по типу с операндами. Рассмотрим преобразование типов, показанное на рисунке.
Char ch;
Int i;
Float f;
Double d;
result = (ch/i) + (f*d) – (f+i);
Cначала символ ch преобразуется к целому int, а вещественная переменная с одинарной точностью f преобразуется к типу double. Затем ch/i преобразуется к типу double, поскольку f*d имеет тип double. Конечный результат имеет тип double, поскольку оба операнда типа double.