1:什么是整形提升?
整形提升是指在C语言中,当较小的整数类型(如
char
、short
)参与表达式运算时,它们会被自动提升为较大的整数类型(如int
或unsigned int
)的过程。整形提升是由C语言标准规定的隐式类型转换规则。当较小的整数类型参与表达式运算时,它们会被自动提升为较大的整数类型,以便进行一致的计算。这样做是为了避免在计算过程中出现意外的精度丢失或溢出。
例如,当一个
char
类型的变量和一个int
类型的变量进行运算时,char
类型的变量会被提升为int
类型,然后再进行运算。这种提升是隐式进行的,程序员无需手动指定。
简单来说,char为1个字节,short为2个字节,他们在参与各个运算时都会系统隐式转换为int类型,4个字节
2:整形提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
//实例1
char a,b,c;
...
a = b + c;b和c的值被提升为普通整型,然后再执行加法运算,加法运算完成之后,结果将被截断,然后再存储于a中。
3:如何进行整形提升?
整形提升是按照变量的数据类型的符号位来提升的
有符号整数提升,高位补符号位,无符号整数提升,高位补0
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:1111111
因为 char 为有符号的 char,所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0
4:整形提升的实例:
例一:
#include<stdio.h>
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d\n", c);
return 0;
}
这个例子能很经典的说明整形提升。首先,它的结果为:
原因: a为char类型,一个字节,3为int类型,4个字节,当3赋给a时,
3在内存中的二进制:00000000000000000000000000000011存储到a中会发生截断,
存储在a中的是:00000011
同理127在内存中的二进制:00000000000000000000000001111111存储到b中会发生截断,
存储在b中的是: 01111111
而char c=a+b这个表达式中,首先会计算a+b,然后再把值赋给c。
对于a+b的运算,因为a,b是有符号的char类型,小于int类型,相加时会发生整形提升,各自先变成整形。
所以a在内存中的二进制会变为: 00000000000000000000000000000011
所以b在内存中的二进制会变为: 000000000000000000000000001111111
相加得到 a+b : 00000000000000000000000010000010
再将a+b赋值给char类型的c时会发生截断,
得到c:10000010
在打印时,因为是%d打印(按十进制整形打印)所以c会整形提升。
因为char是有符号的char,高位为符号位,补符号位1.
所以在内存中打印时,它变为:11111111111111111111111110000010(补码)。
它的原码是 :10000000000000000000001111110 (补码取反再加1得到原码) //即-126
所以打印时得到-126!
例二:
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));
return 0;
}实例1中的,c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字节.表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof(c) ,就是1个字节.
例三:
int main()
{
char a = 0xb6;//十进制为186
short b = 0xb600;//十进制为46592
int c = 0xb6000000;
if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");
return 0;
}
输出结果:c
原因:
char a = 0xb6;
将一个十六进制值整数0xb6
赋给了一个char
类型的变量a
。在C语言中,char
类型是一个整数类型,它通常占用1个字节的内存空间,可以表示-128到127(如果是有符号的)或者0到255(如果是无符号的)范围内的整数值。在这种情况下,
0xb6
是一个8位的十六进制整数,0xb6在内存中的二进制是:00000000000000000000000010110110
放在char类型(因为char是有符号类型,高位为符号位)中会发生截断,所以a中存储的是: 10110110(补码)
它的原码为:11001010 即-74。
所以a中存储的是-74,并非0xb6即186,同理b中存储的也是一个负数,并非0xb600,而对于
int
类型的变量c
,它不需要提升,因为它本身就是int
类型。