C语言-类型转换

类型转换是指把一种类型的数据(变量、数值、表达式的结果等)转换成另一种类型的数据

由于各种数据类型在表示范围精度上是不同的,所以可能会造成精度损失。

各种数据类型的级别如下:(由高到低)

数据类型 意义 字节大小 级别
long double 双精度浮点 8 B 最高
double 双精度浮点 8 B
float 单精度浮点 4 B
unsigned long int(unsigned long) 无符号长整型 4 B
signed long int(long) 有符号长整型 4 B
unsigned int(unsigned) 无符号整型 4 B
signed int(int) 有符号整型 4 B
unsigned short int(unsigned short) 无符号短整型 2 B
signed short(short) 有符号短整型 2 B
unsigned char 无符号字符 1 B
signed char(char) 有符号字符 1 B 最低

助记规律:

  • 浮点类型 > 整型 > 字符类型
  • 长 > ‘ ‘ > 短
  • 无符号 > 有符号

类型转换分为两类:隐式类型转换和显示类型转换

隐式(自动)类型转换

隐式类型转换是在编译时由编译器按照一定规则自动完成的类型转换。

需要注意的是,隐式类型转换并不一定是安全的。对于不安全的类型转换,编译器一般会给出警告(长类型转换为短类型时发生的截断)。

C语言会在以下四种情况下进行隐式类型转换:

(1)赋值表达式

将一种类型的数据赋值给另外一种类型的变量时就会发生隐式类型转换

转换规则:在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型转换为左边变量的类型。这可能会导致数据失真,或者精度降低。

1
2
float f = 100; // 100是int类型的数据,需要先转换为 float 类型才能赋值给变量 f
int n = f; // f 是 float 类型的数据,需要先转换为 int 类型才能赋值给变量 n

(2)算术表达式

转换规则

  • 把表达式中不同类型的数据转换成精度最高、占用内存最多的那个数据类型。
  • 表达式中如果有char、short和enum类型的数据时,自动转换为int类型。(其实是因为运算最终还是要放到通用寄存器中)
  • float类型在运算时一律转换为double类型,以提高运算精度。
1
2
3
4
5
6
char a = 1;
short b = 2;
int c = 3;
float d = 1.1;
int result = a + b + c + d;
// 运算时会将a, b, c, d都转换为double类型再相加

(3)函数调用中参数传递

隐式地将实参转换为形参的类型,然后赋值给形参

(4)函数返回值

隐式地将返回表达式的结果转换为返回值类型,然后赋值给caller函数

显示(强制)类型转换

显示类型转换语法

1
2
3
4
(<目标数据类型>)<原数据类型的数据>
e.g.
(int) 3.14 将浮点数3.14转换成整数3
(double) 4 将4转换成双精度浮点数4.0

数据类型的扩充与截断

一、小数据类型 -> 大数据类型

数据类型扩充:发生在占用内存空间小的整型变量赋值给占用内存空间大的整型变量的情况。

这种情况下,较小的数据类型的值、正负均不变,数据不失真

转换规则:

  • 如果原数据类型为无符号整型,进行零扩展
  • 如果原数据类型为有符号整型,进行符号扩展

注意:与目标数据类型无关!!!

二、大数据类型 -> 小数据类型

数据类型截断:发生在占用内存空间小的整型变量赋值给占用内存空间大的整型变量的情况。

这种情况下,数据可能会失真

转换规则:

  • 无论原数据类型有无符号,丢弃高位数据。

三、一样大小的数据类型相互转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//例子
char c = 128; // 存储空间:0b1000_0000 char的角度看是-1
unsigned char uc = 128; // 0b1000_0000 unsigned char的角度看是128
unsigned short ushort;

ushort = (unsigned short)c + uc;
//翻译成汇编后,这一条语句做的事情如下
/*
* Step 1
将c从char强制类型转换为unsigned short,需要进行扩展,原数据类型是有符号的,所以进行符号扩展
0b 1000_0000 => 0b 1111_1111_1000_0000 unsigned short的角度看是一个很大的数
* Step 2
将c从unsigned short隐式转换为int,需要进行扩展,原数据类型是无符号的,所以进行零扩展
0b 1111_1111_1000_0000 => 0b 0000_0000_0000_0000_1111_1111_1000_0000
将uc从unsigned char隐式转换为int,需要进行扩展,原数据类型是无符号的,所以进行零扩展
0b1000_0000 => 0b 0000_0000_0000_0000_0000_0000_1000_0000
* Step 3
进行加法
0b 0000_0000_0000_0000_1111_1111_1000_0000
+0b 0000_0000_0000_0000_0000_0000_1000_0000
=0b 0000_0000_0000_0001_0000_0000_0000_0000
* Step 4
由于左值是unsigned short,空间为2B,所以取最低的2B,即 0b 0000_0000_0000_0000,unsigned short的角度看是0
*/

参考链接🔗:

一些数据类型转换的例子:【C语言】数据类型的扩充和截断_以数据内部存储格式说明计算机中不同数据类型之间转换截断的概念-CSDN博客