Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

prog / Лекции / 12. Продвижение типов

.pdf
Скачиваний:
25
Добавлен:
13.05.2015
Размер:
133.05 Кб
Скачать

Продвижение типов

Продвижением типов называется автоматическое приведение типов операндов при вычислении значений бинарных операций в выражениях. Продвижение типов преобразует значения операндов к некоторому одному типу, так как большинство бинарных операций может быть выполнено только над двумя операндами одного типа, например int–int, double–double и т.д., а не int–double и т.п. Это, с одной стороны, упрощает реализацию компилятора (каждая операция реализуется только для пар одноименных типов данных, а не для всех возможных пар) и, с другой, избавляет программиста от необходимости выполнять приведение типов операндов самостоятельно. Во многих случаях тип результата операции также зависит от типов операндов.

В спецификации языка C и во многих справочных и учебных пособиях описание продвижения типов представлено в виде свода правил «если… то…», однако этот механизм можно представить следующей диаграммой:

char

unsigned char

short

unsigned short

int

unsigned int

long unsigned long

float

double

long double

Преобразование типа операнда выполняется обязательно и независимо от типа другого операнда.

Преобразование типа операнда выполняется только в том случае, если другой операнд беззнаковый.

Преобразование типа операнда выполняется во всех остальных случаях, если другой операнд имеет другой тип.

Из диаграммы видно, что продвижение типов выполняется всегда от меньших типов к большим, имеющим не меньшие диапазоны значений, точности и порядка, чтобы значение операнда не было искажено (исключение – преобразование целочисленного отрицательного значения в беззнаковое). При этом преобразование значений и их интерпретация выполняются по тем же правилам, что и приведение типов. В приведенной ниже таблице представлены примеры продвижения типов, наглядно демонстрирующие, что результирующий тип выбирается при движении по диаграмме в направлении стрелок, до типа, ближайшего к исходным:

Исходные типы операндов

Результирующий тип

char

int

int

int

double

double

int

unsigned int

unsigned int

float

int

double

unsigned int

long

unsigned long

char

unsigned char

unsigned int

unsigned short

long double

long double

Следует учитывать, что это общая схема продвижения типов, но к бинарным операциям разных групп (по назначению) она применима в различной степени:

операнды арифметических операций приводятся к одному типу и результат будет иметь тот же тип;

операнды логических поразрядных операций (кроме двоичного сдвига) приводятся к одному типу и результат будет иметь тот же тип;

операнды операций двоичного сдвига не приводятся к одному типу, а результат имеет тот же тип, что и левый операнд;

операнды операций отношения приводятся к одному типу, но результат всегда имеет тип int (логическое значение);

операнды логических операций не приводятся к одному типу и рассматриваются как логические независимо друг от друга, а результат всегда имеет тип int (логическое значение);

правый операнд операции простого присваивания приводится к типу левого операнда и результат будет иметь тот же тип;

операнды операций сложного присваивания приводятся к одному типу и выполняется арифметическая или поразрядная операция, результат которой приводится к типу левого операнда и результат будет иметь тот же тип;

операнды операции «запятая» не приводятся к одному типу, а тип результата будет соответствовать типу правого операнда.

Так как в выражениях при выполнении операций могут сочетаться продвижение

типов, явное и неявное их приведение, то результат вычислений может оказаться несколько неожиданным, например:

int a = –3; unsigned int b = 1; long c;

c = a + b;

С математической точки зрения: –3 + 1 = –2. Однако в приведенном примере переменная c примет значение 65534:

1.при определении переменной b значение 1 типа int будет приведено к беззнаковому и не изменится;

2.при вычислении a+b в результате продвижения типов значения операндов будут

приведены к типу unsigned int, при этом левый операнд станет равен

–310 = 1111'1111'1111'11012 → 1111'1111'1111'11012 = 6553310;

3.в результате суммирования будет получен результат 65534 типа unsigned int;

4.при выполнении присваивания, полученный результат будет приведен к типу long, причем при его расширении, как беззнакового, старшие разряды будут заполнены нулями и число интерпретируется как положительное.

Вподобных случаях, зная механизм продвижения типов и правила преобразования значений, проблему можно легко решить либо явным приведением типов (например,

используя (long)a или (int)b в последнем выражении), либо выбором других типов данных при определении переменных.