整型提升的含义
C语言的整形算术运算总是至少已缺省整型类型的精度来进行,为了获得这种精度,表达式中的字符和短整型操作数,在进行使用前需要转化为普通整形,这种转化称为整型提升。
我的理解即是:一个整形数据有四个字节,32个比特位,而像字符型或者短整型这种数据,他们不够32个比特位,因此需要提升到32位。
进行整型提升的原因
整型算术运算要在计算机cpu内的整型运算器中进行。而整型运算器的操作数字节长度是整形int的字节长度。所以在整型计算时,要将所有数据提升至整形int的字节长度32位,即4字节。
整型提升的过程
首先我们先来看一串代码:
#include<stdio.h> int main() { char a = -1; signed char b = -1; unsigned char c = -1; char d = 1; printf("a=%d,b=%d,c=%d,d=%d", a, b, c,d); return 0; }
再讲解该过程之前,大家先想想输出结果是什么?我猜,有一部分人会认为是-1、-1、-1、1.没错,我在不了解整形提升之前也是这么认为的。
现在我们让代码运行,看看结果是多少:
咦?为什么会出现255呢?仔细看这里的三个变量都是字符型数据,并不是int,但最终以%d的形式输出,难道出现的255是与整型提升有关吗?
下面我们通过了解整型提升的过程来解开这个疑惑!上面我们仅仅了解到了整型提升的定义和原因,那么到底是如何进行提升的呢
以普通字符型进行举例:
char a = -1;
通过前面的学习我么知道数据在内存中是以补码的形式存储,所以我们先写出变量a的补码:
//原码:10000000000000000000000000000001
通过原码写出反码(符号位不变,其他按位取反)
//反码:11111111111111111111111111111110
通过反码写出补码(反码+1)
//补码:11111111111111111111111111111111
然后进行截断,截断的长度为char的长度,一个字节
得到:11111111
下面进行整型提升:规则是(有符号数据类型,最高位代表符号位,则直接补符号位,无符号数据类型,则直接补0)
这里的char,没说是unsigned char吧?因此我们默认他为有符号数
提升后的结果:11111111111111111111111111111111为该数据的补码
由于它是负数,所以我们需要倒推,通过补码找原码
//反码:11111111111111111111111111111110(补码减一)
//原码:1000000000000000000000000001(符号位不变,按位取反)
输出结果即为-1
以有符号字符为例进行举例:
signed char b = -1;
和上面的分析过程几乎一模一样,只不过这里有符号的特征比较明显,在定义的时候明确指出。
以无符号字符为例进行举例:
unsigned char c = -1
和上面一样我们先写出变量c的补码:
//原码:10000000000000000000000000000001
通过原码写出反码(符号位不变,其他按位取反)
//反码:11111111111111111111111111111110
通过反码写出补码(反码+1)
//补码:11111111111111111111111111111111
然后进行截断,截断的长度为char的长度,一个字节
得到:11111111
注意:这里和上面就不同了,由于它是无符号数据类型,所以补0
提升之后的结果为:00000000000000000000000011111111为该数提升之后的补码,由于它是无符号数据类型,因此最高位并不代表符号位,所以它的原码反码补码相同。
输出结果为255
以正数为例进行举例:
char d = 1;
和上面一样我们先写出变量d的补码:由于该数为正数所以它的原码反码补码相同
//原码/反码/补码:00000000000000000000000000000001
然后进行截断,截断的长度为char的长度,一个字节
得到:00000001下面进行整型提升:这里的char,没说是unsigned char吧?因此我们默认他为有符号数提升后的结果:00000000000000000000000000000001为该数据的补码,由于该数为正数所以它的原码反码补码相同
输出结果为1
short类型进行整型提升的时候是如何进行的?
其实它的步骤和char基本相同,差别在于,截断过程,char类型截断8个比特位,因为它是一个字节,而short截断16个比特位,因为它是2个字节。
下面通过具体的示例进行演示:
unsigned short c = -1;
和上面一样我们先写出变量c的补码:
//原码:10000000000000000000000000000001
通过原码写出反码(符号位不变,其他按位取反)
//反码:11111111111111111111111111111110
通过反码写出补码(反码+1)
//补码:11111111111111111111111111111111
然后进行截断,截断的长度为short的长度,两个字节
得到:1111111111111111
注意:由于它是无符号数据类型,所以补0
提升之后的结果为:00000000000000001111111111111111为该数提升之后的补码,由于它是无符号数据类型,因此最高位并不代表符号位,所以它的原码反码补码相同。
输出结果为65535
其他的signedshort和short也是类似的步骤和方法,这里就不过多赘述了。
那整型提升会在哪里用到呢?
还是用上面的变量举例,当字符型数据进行整形运算时,不能直接进行代数和的相加减乘除,必须先进行整型提升,之后再进行代数和的相加减乘除。
以char为例进行举例:
#include<stdio.h> int main() { char a = -1; signed char b = -1; unsigned char c = -1; char d = 1; printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c,d); printf("a+b=%d\na+c=%d\na+d=%d\nb+c=%d\nb+d=%d\nc+d=%d\n",a+b, a + c,a+d,b+c,b+d,c+d); return 0; }
输出结果如下所示:
以short为例进行举例:
#include<stdio.h> int main() { short a = -1; signed short b = -1; unsigned short c = -1; short d = 1; printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c,d); printf("a*b=%d\na+c=%d\na+d=%d\nb+c=%d\nb+d=%d\nc+d=%d\n",a*b, a + c,a+d,b+c,b+d,c+d); return 0; }