Типы в выражениях можно “смешивать”. Например, выражение 2.5/2
означает деление переменной типа double
на переменную типа int
. Что это значит? Какое деление выполняется: целых чисел или с плавающей точкой? Целочисленное деление отбрасывает остаток, например 5/2
равно 2
. Деление чисел с плавающей точкой отличается тем, что остаток в его результате не отбрасывается; например 5.0/2.0
равно 2.5
. Следовательно, ответ на вопрос “Какие числа делятся в выражении 2.5/2
: целые или с плавающей точкой?” совершенно очевиден: “Разумеется, с плавающей точкой; в противном случае мы потеряли бы информацию”. Мы хотели бы получить ответ 1.25
, а не 1
, и именно 1.25
мы и получим. Правило (для рассмотренных нами типов) гласит: если оператор имеет операнд типа double
, то используется арифметика чисел с плавающей точкой и результат имеет тип double
; в противном случае используется целочисленная арифметика, и результат имеет тип int
.
5/2 равно 2 (а не 2.5)
2.5/2 равно 2.5/double(2), т.е. 1.25
'a'+1 означает int('a')+1
Иначе говоря, при необходимости компилятор преобразовывает (“продвигает”) операнд типа int
в операнд типа double
, а операнд типа char
— в операнд типа int
. Вычислив результат, компилятор может преобразовать его снова для использования при инициализации или в правой части оператора присваивания. Рассмотрим пример.
double d = 2.5;
int i = 2;
double d2 = d/i; // d2 == 1.25
int i2 = d/i; // i2 == 1
d2 = d/i; // d2 == 1.25
i2 = d/i; // i2 == 1
Будьте осторожны: если выражение содержит числа с плавающей точкой, можно легко забыть о правилах целочисленного деления. Рассмотрим обычную формулу для преобразования температуры по Цельсию в температуру по Фаренгейту: f = 9/5*с+32
. Ее можно записать так:
double dc;
cin >> dc;
double df = 9/5*dc+32; // осторожно!
К сожалению, несмотря на вполне логичную запись, это выражение не дает точного преобразования шкалы: значение 9/5
равно 1
, а не 1.8
, как мы рассчитывали. Для того чтобы формула стала правильной, либо 9
, либо 5
(либо оба числа) следует представить в виде константы типа double
.
double dc;
cin >> dc;
double df = 9.0/5*dc+32; // лучше
4.4. Инструкции
Выражение вычисляет значение по набору операндов, используя операторы наподобие упомянутых в разделе 4.3. А что делать, если требуется вычислить несколько значений? А что, если что-то необходимо сделать многократно? А как поступить, если надо сделать выбор из нескольких альтернатив? А если нам нужно считать входную информацию и вывести результат? В языке С++, как и во многих языках программирования, для создания таких выражений существуют специальные конструкции.
До сих пор мы сталкивались с двумя видами инструкций: выражениями и объявлениями. Инструкции первого типа представляют собой выражения, которые завершаются точкой с запятой.
a = b;
++b;
Выше приведен пример двух инструкций, представляющих собой выражения. Например, присваивание =
— это оператор, поэтому a=b
— это выражение, и для его завершения необходимо поставить точку с запятой a=b
; в итоге возникает инструкция. Зачем нужна точка с запятой? Причина носит скорее технический характер.
Рассмотрим пример.
a = b ++ b; // синтаксическая ошибка: пропущена точка с запятой
Без точки с запятой компилятор не знает, что означает это выражение: a=b++; b;
или a=b; ++b;
. Проблемы такого рода не ограничиваются языками программирования. Например, рассмотрим выражение “Казнить нельзя помиловать!” Казнить или помиловать?! Для того чтобы устранить неоднозначность, используются знаки пунктуации. Так, поставив запятую, мы полностью решаем проблему: “Казнить нельзя, помиловать!” Когда инструкции следуют одна за другой, компьютер выполняет их в порядке записи. Рассмотрим пример.
int a = 7;
cout << a << '\n';
Здесь объявление с инициализацией выполняется до оператора вывода. В целом мы хотим, чтобы инструкция имела какой-то эффект. Без эффекта инструкции, как правило, бесполезны. Рассмотрим пример.
1+2; // выполняется сложение, но сумму использовать невозможно
a*b; // выполняется умножение, но произведение не используется
Такие инструкции без эффекта обычно являются логическими ошибками, и компиляторы часто предупреждают программистов об этом. Таким образом, инструкции, представляющие собой выражения, обычно являются инструкциями присваивания, ввода-вывода или вызова функции.