Информатика и технология программирования

       

Преобразование типов операндов


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



-увеличение или уменьшение разрядности машинного слова, то есть " усечение" или " растягивание" целой переменной;



-преобразование целой переменной в переменную с плавающей точкой и наоборот;



-преобразование знаковой формы представления целого в беззнаковую и наоборот.

Уменьшение разрядности машинного слова всегда происходит путем отсечения старших разрядов числа. Заметим, что это может привести к ошибкам потери значащих цифр и разрядов:


int n=0x7654;
char c; c = n; // Потеря значащих цифр (0x54)

Увеличение разрядности приводит к появлению дополнительных старших разрядов числа. При этом способ их заполнения зависит от формы представления целого:



-для беззнаковых целых заполнение производится нулями;



-для целых со знаком они заполняются значением знакового (старшего) разряда.

Таким образом, при увеличении размерности целого его значение сохраняется:




int n; unsigned u;
char c=0x84; n = c; // Значение n=0xFF84


unsigned char uc=0x84; u = uc; // Значение u=0x0084

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


double d1=855.666, d2=0.5E16;
int n; n = d1; // Отбрасывание дробной части


n = d2; // Потеря значимости

Преобразование знаковой формы к беззнаковой не сопровождается изменением значения целого числа и вообще не приводит к выполнению каких-либо действий в программе.
В таких случаях транслятор "запоминает", что форма представления целого изменилась:



int n=-1;
unsigned d; d = n; // Значение d=0xFFFF (-1)



Самое главное для программиста, что в языке не предусмотрены средства автоматической реакции на ошибки преобразования типов данных, поэтому " отлавливать" их должна сама программа.

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


-при выполнении операции присваивания, когда значение переменной или выражения из правой части запоминается в переменной в левой части (см. Операция присваивания);


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


-при выполнении бинарных операций над операндами различных типов, когда более " длинный" операнд превалирует над более " коротким" , вещественное -над целым, а беззнаковое над знаковым.

Соответствующие неявные преобразования выполняются в такой последовательности.

.

1. . char,short,enum,битовое поле,unsigned char,
unsigned short -&#62 int
float -&#62 double
2. long double + x -&#62 long double+long double
double + x -&#62 double + double
long + x -&#62 long + long
unsigned + x -&#62 unsigned + unsigned
3. int + int -&#62 int + int





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

Следует обратить внимание на одну тонкость: если в процессе преобразования требуется увеличение разрядности переменной, то на способ ее "удлинения" влияет только наличие или отсутствие знака у самой переменной.


Второй операнд, к типу которого осуществляется приведение, на этот процесс не влияет:



long l=0x21;
unsigned d=0xFF00;
l + d ...
// 0x00000021 + 0xFF00 = 0x00000021 + 0x0000FF00 = 0x0000FF21



В данном случае производится преобразование целого обычной точности без знака (unsigned) к длинному целому со знаком (
long). В процессе преобразования "удлинение" переменной d производится как беззнаковое (разряды заполняются нулями), хотя второй операнд и имеет знак. Рассмотрим еще несколько примеров.



int i; i = 0xFFFF;





Целая переменная со знаком получает значение
FFFF , что соответствует -1 для знаковой формы в дополнительном коде. Изменение формы представления с беззнаковой на знаковую не сопровождается никакими действиями.



int i = 0xFFFF;
long l; l = i;







Преобразование int в long сопровождается " удлинением" переменной, что с учетом представления i со знаком дает
FFFFFFFF , то есть длинное целое со значением -1 .



unsigned n = 0xFF00;
long l; l = n;

Переменная n " удлиняется" как целое без знака, то есть переменная l получит значение 0000FF00 .

int i; unsigned u;
i = u = 0xFFFF;
if (i &#62 5) ... // "Ложь"

if (u &#62 5) ... // "Истина"





Значения переменных без знака и со знаком равны FFFF или - 1 . Но результаты сравнения противоположны, так как во втором случае сравнение проводится для беззнаковых целых по их абсолютной величине, а в первом случае -путем проверки знака результата вычитания, то есть с учетом знаковой формы представления чисел.


Содержание раздела