什么是整型提升
C语言中整型算数运算总是以整型类型的精度来进行的。表达式中的字符和短整型操作数在使用之前被 转化为普通整型,这种转换称为整型提升。
为什么会存在整型提升?
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度⼀般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purposeCPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
如何进行整型提升
有符号整数提升是按照变量的数据类型的符号位来提升的
当我们对变量进行赋值的时候,
会先化为32位,然后进行截断
例如char num = -129
,高位是1,然后低位是129,对应二进制就是10000000 00000000 00000000 1000 0001
,因为-129是负数,所以取补码就是11111111 11111111 11111111 0111 1111
然后截取后八位存入。所以内存中存入的是0111 1111
,然后输出之前,会进行整型提升,因为类型是char且高位是0,所以补符号位,前面全部补0,对应二进制为00000000 00000000 00000000 0111 1111
,如果以d%形式输出最会就会输出127。
给变量赋值的时候不关心类型,类型只是代表多大的空间。(有一点需要注意,我们在给变量赋值的时候确实有一个类型检查的动作,比如我们在整型赋值一个浮点数的时候,会直接截断赋值,而不是按照浮点数存储方式存入的)
例如:
当我们对变量进行赋值的时候,
例如char num = 129
。二进制是00000000 00000000 00000000 1000 0001
,因为高位为0为正数,所以直接截取后八位然后存入。但是当输出的时候,会因为高位是1,且是char类型,会进行整型提升,前面补符号位1
,最后就是11111111 11111111 11111111 1000 0001
然后将此数认为是补码,如果是以d%的形式进行打印,d%是有符号数,所以要取原码就是10000000 00000000 00000000 0111 1111
,结果就是对应的十进制-127。
如果是以u%的形式进行打印,u%是无符号数,就认为整型提升后得到的就是无符号数。就直接输出二进制11111111 11111111 11111111 1000 0001
对应的结果就是对应的十进制是一个很大的数。
变量类型在输出前整型提升的时候得到体现,如果是有符号类型高位就补符号位,无符号类型就补0。
结论::在赋值的时候会按照32位的值进行赋值,赋值的时候不关心变量类型,然后截断。整型提升的时候才关心类型。输出的时候根据变量类型采取不同的提升方法。然后输出的时候按照d%还是u%来确定是否要再次取补码。
存数取数和最后输出都要注意
无符号数整型提升,高位补0
int main()
{
char a = 5;
char b = 126;
char c = a + b;
printf("%d\n", a + b);
printf("%d\n", c);
unsigned char m = 245;
unsigned char n = 12;
unsigned char p = m + n;
printf("%d\n", m + n);
printf("%d", p);
char q = 0xF0;
printf("%d\n", q);
return 0;
}
如上代码输出:
第一个printf输出a + b的值,就是131。%d是按照10进制打印有符号数。
第二个printf输出c的值
a,b在参与运算之前进行整型提升为
a:000000000000000000000000 0000 0101
b:000000000000000000000000 0111 1110
高位补符号位
截取后面8位存储在a和b中
二者相加为1000 0011
然后进行整型提升,整型提升高位为符号位
111111111111111111111111 1000 0011
因为计算机以补码存储,所以相加也是补码相加,且相加后高位为1,所以认为得到的就是c的补码。
然后找其原码
100000000000000000000000 0111 1101
最后就输出-125
整型提升和CPU运算器有关系,在其他架构的CPU上整型提升可能不一样,跑出来的结果也可能不一样。
第三个printf输出输出m + n的值,就是131。
第四个printf输出p的值
m:000000000000000000000000 1111 0101
n:000000000000000000000000 0000 1100
m + n:
000000000000000000000001 0000 0001
因为是无符号数,所以不变,直接截断,输出1
第五个printf
在我们输入整型常量的时候,默认无符号值,直接就把给的0xF0输入,但是我们的变量是char类型,有符号,就默认高位是符号位,输出的时候会对原来的值取反然后加1,就是0xF0的补码。就是-16
还有一点需要注意的是整型提升不发生在浮点数的类型中