Если в арифметических операциях участвуют значения разных типов, то компилятор неявно пытается привести их к одному типу. Кроме того, когда мы присваиваем переменной какое-либо значение, это значение всегда приводится к типу переменной. Например:
char c = 6; int d = c;
Переменной d, которая представляет тип int, присваивается значение типа char, поэтому компилятор выполняет приведение значения от типа char к типу int.
В то же время не всегда преобразования могут быть безопасными, поскольку разные типы имеют разное внутреннее представление. И просто так перейти от одного представления к другому без потери точности данных не всегда возможно.
Рассмотрим, какие преобразования применяет компилятор при арифметических операциях:
Если один из операндов имеет тип long double, то второй операнд тоже будет преобразован в тип long double
Если предыдущий пункт не выполняется и если один из операндов имеет тип double, то второй операнд тоже будет преобразован к типу double
Если предыдущий пункт не выполняется и если один из операндов имеет тип float, то второй операнд тоже будет преобразован к типу float
Если предыдущий пункт не выполняется и если один из операндов имеет тип unsigned long int, то второй операнд тоже будет преобразован к типу unsigned long int
Если предыдущий пункт не выполняется и если один из операндов имеет тип long, то второй операнд тоже будет преобразован к типу long
Если предыдущий пункт не выполняется и если один из операндов имеет тип unsigned, то второй операнд тоже будет преобразован к типу unsigned
Если предыдущий пункт не выполняется то оба операнда приводятся к типу int
Например:
int a = 10; #include <stdio.h> int main(void) { int number1 = 10; double number2 = 4; double result = number1 + number2; // 14.000000 printf("result = %f \n", result); // result = 14.000000 return 0; }
В выражении number1 + number2
число number2
представляет тип double, поэтому число number1
будет автоматически приводиться к числу double. И результат операции сложения также будет представлять тип double.
С помощью специальной операции преобразования мы можем явным образом привести данные к нужному типу. Например:
int a = 10; int b = 4; int c = a / b; // 2 double d = a / b; // 2.00000 double e = (double)a / (double)b; // 2.50000 printf("c = %d \n", c); printf("d = %f \n", d); printf("e = %f \n", e);
В выражении int c = a / b;
результат деления будет целочисленный - 2, при котором дробная часть будет отброшена, так как оба операнда операции представляют целые числа.
В выражении double d = a / b;
результат деления будет представлять вещественное число - 2.00000, но так как оба операнда являются целыми числами, то опять же результат операции будет представлять целое число 2, и только поле выполнения деления произойдет
присвоение результата переменной d с приведением значения 2 от типа int к типу double.
В выражении double e = (double)a / (double)b
применяется явное преобразование данных к типу double, поэтому и результат деления
будет представлять вещественное число - 2.50000.
Для выполнения операции приведении в скобках указывается тот тип, к которому надо привести значение:
int number = 70; char symbol = (char) number; printf("symbol = %c \n", symbol); // F printf("symbol (int code) = %d \n", symbol); // 70
В ряде случаев преобразования сопровождаются потерей информации, например, когда числа большей разрядности (скажем размером 4 байт) получаем число меньшей разрядности (например, в 2 байта). Без потери информации проходят следующие цепочки преобразований:
char -> short -> int -> long
unsigned char -> unsigned short -> unsigned int -> unsigned long
float -> double -> long double
При всех остальных преобразованиях, которые не входят в эти цепочки, мы можем столкнуться с потерей точности данных. Так, в примере выше преобразование от int к char не является безопасным, поэтому к таким преобразованиям следует относиться с осторожностью. Например:
#include <stdio.h> int main(void) { int number1 = 300; char code = number1; // потеря точности - число number1 усекается до 1 байта printf("code = %d \n", code); // code = 44 return 0; short number2 = 100000; // потеря точности - число 100000 усекается до 2 байт printf("number2 = %d \n", number2); // number2 = -31072 }
Здесь две ситуации небезопасных преобразований. В первом случае число типа int
, которое равно 300, присваивается переменной типа char
. В итоге переменная code
будет равна 44. Почему? Число
300 в двоичной системе:
0000000100101100
Оставляем только первый младший байт:
00101100
И у нас получается число 44 в десятичной системе.
Во втором случае число 100000 (которое по умолчанию представляет тип int
), усекается до разрядности типа short
-
до двух байт.
short number = 100000;
В итоге число number
в реальности будет равно -31072.