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

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

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

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

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

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

int n=0x7654;

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

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

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

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

int n; unsigned u;

// Значение n=0xFF84

char с=0х84; n= с;

//Значение u=0x0084

unsigned char uc=0x84; u = uc;

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

double d1 =855.666, d2=0.5E16;

int n;

n = d1; // Отбрасывание дробной части

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

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

int n = -1;

unsigned d;

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

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

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

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

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

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

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

Следует обратить внимание на одну тонкость: если в процессе преобразования требуется увеличение разрядности переменной, то на способ ее «удлинения» влияет только наличие или отсутствие знака у самой переменной. Второй операнд, к типу которого осуществляется приведение, на этот процесс не влияет:

long k=0x21;

unsigned short d=0xFF00;

//0x00000021 + 0xFF00 =

//=0x00000021 + 0x0000FF00 = 0x0000FF21

cout<<hex<<k + d<<’\n’;

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

Рассмотрим еще несколько примеров.

int i; i=0xFFFF;

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

short i = 0xFFFF;

int k; k=i;

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

unsigned short n =0xFF00;

int i;

i = n;

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

short i; unsigned short u;

i = u= 0xFFFF;

if (i > 5) … // "Ложь"

if (u > 5)... // "Истина"

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

 

Стандартные программные решения


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: