Программирование и основы алгоритмизации УТС / Лекции / 11. Приведение типов
.pdfПриведение типов
Приведением типа называют преобразование значения некоторого типа к другому типу, при этом может измениться формат представления данных в оперативной памяти ЭВМ или способ их интерпретации.
Приведение типа может выполняться явно (при помощи операции приведения типа) или неявно (при присваивании значений или при передаче значений в качестве параметров при вызове функции). Случаи неявного приведения типов операндов бинарных операций к одному типу называют продвижением типов.
Операция приведения типа является унарной и имеет вид: (<тип>)<выражение>. В следующем примере использована операция приведения типа целочисленной переменной a к типу double, чтобы результат деления двух целых чисел был вещественным. Значение выражения (double)a будет иметь тип double и будет равно 5.0, а результат деления – 1.66666666667 (это значение и будет присвоено переменной c). В последней строке операция приведения типа в выражении отсутствует и деление является целочисленным, поэтому его результат равен 1 (только целая часть частного) и это значение будет присвоено переменной d, т.е. дробная часть результата будет потеряна несмотря на то, что переменная d имеет тип double. Здесь, кстати, будет иметь место неявное приведение типа – целочисленное значение 1 будет приведено к значению 1.0 типа double.
int a = 5, b = 3; double c, d;
c = (double)a / b; d = a / b;
В случае вызова функции, приведение типа может быть выполнено автоматически (неявно), если при компиляции доступно описание этой функции (например, включен соответствующий заголовочный файл):
int x = 1; float y;
y = sin(x);
В данном примере x является аргументом функции sin, которая требует параметр типа double, к которому и будет приведено значение этого целочисленного аргумента. Функция возвращает значение типа double, но при его присваивании переменной y типа float опять произойдет неявное приведение типа. В результате вызов функции и интерпретация значений выполняются правильно, но только в том случае, если включен заголовочный файл math.h, иначе приведения типа в обоих случаях не выполнятся и функция будет вызвана неправильно (результат вычислений будет непредсказуем – от неверного значения вычислений до ошибки во время выполнения программы).
При выполнении приведения типов формат представления значения или его интерпретация изменяются в зависимости от того, какими являются исходный и конечный типы. При этом возможны следующие ситуации:
1. Приведение целочисленного значения к беззнаковому:
char |
→ unsigned char |
||
short |
→ unsigned short |
||
int |
→ |
unsigned |
int |
long |
→ |
unsigned |
long |
Двоичное представление не изменяется, но меняется трактовка знакового разряда числа – он становится просто старшим разрядом двоичного неотрицательного числа. Например, при приведении значения –210 = 1111'1111'1111'11102 (рамкой обозначен знаковый разряд) типа int к типу unsigned int, двоичное представление и его размер не изменятся. Однако, полученное значение будет интерпретироваться как положительное: 1111'1111'1111'11102 = 6553410 (знаковый разряд отсутствует и
старший разряд двоичного представления эквивалентен 215 = 32768, т.е. число равно
1·215 + 1·214 + … + 1·22 + 1·21 + 0·20).
2. Приведение беззнакового значения к целочисленному со знаком:
unsigned char |
→ char |
||
unsigned short |
→ short |
||
unsigned |
int |
→ |
int |
unsigned |
long |
→ |
long |
Этот процесс является обратным рассмотренному: двоичное представление числа не изменится, но старший разряд будет рассматриваться как знаковый.
3. Приведение целочисленного значения к большему по размеру целому типу:
char |
→ int |
|
|
short |
→ |
int |
|
int |
→ |
long |
и т.п. |
Значение расширяется за счет заполнения старших («новых») разрядов двоичного представления числа значением его знакового разряда:
0100'00112 (+6710) → 0000'0000'0100'00112 (+6710)
1011'11012 (–6710) → 1111'1111'1011'11012 (–6710)
4. Приведение целочисленного беззнакового значения к большему по размеру целому беззнаковому типу:
unsigned char |
→ unsigned int |
|
|||
unsigned |
short |
→ |
unsigned |
int |
|
unsigned |
int |
→ |
unsigned |
long |
и т.п. |
Значение расширяется за счет заполнения старших («новых») разрядов двоичного представления числа нулями:
1011'11012 (18910) → 0000'0000'1011'11012 (18910) 0100'00112 (6710) → 0000'0000'0100'00112 (6710)
Очевидно, что дописывание к числу нулей слева не изменяет значение числа, т.к. эти нули являются незначащими.
5. Приведение целочисленного значения к меньшему по размеру целому типу:
long |
→ int |
unsigned long |
→ unsigned int |
|
||||
int |
→ |
short |
unsigned |
int |
→ |
unsigned |
short |
|
int |
→ |
char |
unsigned |
int |
→ |
unsigned |
char |
и т.п. |
Значение просто усекается до требуемого количества разрядов за счет отбрасывания старших разрядов двоичного представления числа вне зависимости от того, является число знаковым или беззнаковым и каково значение знакового разряда, если он есть:
0000'0000'0100'00112 |
(6710) |
→ 0100'00112 |
(6710) |
0000'0001'0100'00112 |
(32310) |
→ 0100'00112 |
(6710) |
0000'0000'1011'11012 |
(18910) |
→ 1011'11012 |
(–6710) |
1111'1111'1011'11012 |
(–6710) |
→ 1011'11012 |
(–6710) |
1111'1111'0100'00112 (–18910) |
→ 0100'00112 |
(6710) |
6. Приведение целочисленного значения к типу с плавающей точкой:
int |
→ float |
|
|
long |
→ float |
|
|
long |
→ |
double |
|
int |
→ |
long double |
и т.п. |
Значение дополняется нулевой дробной частью и нулевым порядком, после чего нормализуется по правилам конечного типа.
7. Приведение значения с плавающей точкой к целочисленному типу:
float |
→ int |
|
|
float |
→ long |
|
|
double |
→ |
long |
|
long double → |
int |
и т.п. |
Порядок исходного числа приводится к нулю за счет сдвига десятичной (двоичной) точки, после чего дробная часть отбрасывается, а оставшаяся целая часть усекается до
требуемого количества разрядов отбрасыванием «лишних» левых разрядов двоичного представления, если полученное целочисленное значение лежит за пределами диапазона значений конечного типа.
8. Приведение значения с плавающей точкой к большему по размеру типу:
float → double float → long double double → long double
В этом случае увеличивается количество двоичных разрядов, отводимых для представления как мантиссы, так и порядка числа. Правые («новые») разряды мантиссы заполняются нулями (нули, дописываемые справа к дробной части являются незначащими), а порядок расширяется по правилам целого числа со знаком.
m |
|
|
n |
|
||
m |
| 0 0/1 | n |
|||||
|
|
|
|
|
|
|
9. Приведение значения с плавающей точкой к меньшему по размеру типу:
long |
double → double |
||
long |
double |
→ |
float |
double |
→ |
float |
В этом случае уменьшается количество двоичных разрядов, отводимых для представления как мантиссы, так и порядка числа. Мантисса усекается справа до требуемого количества разрядов, т.е. младшие («лишние») разряды отбрасываются (уменьшается количество значащих разрядов – уменьшается точность числа), а порядок усекается слева по правилам целого числа со знаком.
m | |
|
|
|
| n |
||
|
|
X |
|
|
|
X |
m' |
|
|
n' |
|
Если порядок числа велик по модулю и не представим конечным типом, то генерируется сообщение об ошибке во время выполнения, а выполнение программы прерывается.