Преобразование типов операндов
-увеличение или уменьшение разрядности машинного слова, то есть " усечение" или " растягивание" целой переменной;
-преобразование целой переменной в переменную с плавающей точкой и наоборот;
-преобразование знаковой формы представления целого в беззнаковую и наоборот.
Уменьшение разрядности машинного слова всегда происходит путем отсечения старших разрядов числа. Заметим, что это может привести к ошибкам потери значащих цифр и разрядов:
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 -> int
float -> double
2. long double + x -> long double+long double
double + x -> double + double
long + x -> long + long
unsigned + x -> unsigned + unsigned
3. int + int -> 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 > 5) ... // "Ложь"
if (u > 5) ... // "Истина"
Значения переменных без знака и со знаком равны FFFF или - 1 . Но результаты сравнения противоположны, так как во втором случае сравнение проводится для беззнаковых целых по их абсолютной величине, а в первом случае -путем проверки знака результата вычитания, то есть с учетом знаковой формы представления чисел.