本文将会介绍C语言中的隐式的整型提升
一、什么是整型提升
在C中是存在隐式类型转换的,就是在C中的整型算数运算总是至少以缺省整型类型的精度来进行相关操作,为了获得这个精度,表达式中的字符和短整型都必须要转化为普通整型。
二、为什么需要整型提升
整型提升的意义在于:表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。这样就使得非整型的运算可行。
三、如何进行整型提升
以下操作在windows vs2019 x86环境下进行
不妨先看一下这段代码:
int main()
{
char a, b, c;
a = 1, b = 127;
c = a + b;
printf("%d", c);
return 0;
}
按照常理,c应该是128,但是结果如下:
这是因为:
1(10进制) =00000000 00000000 00000000 00000001(二进制补码)
127(10进制)=00000000 00000000 00000000 01111111 (二进制补码)
但是由于a和b默认是signed char类型的数,表示是有符号的字符类型,由于char类型的变量大小为一个字节,即八位,并且最高位表示的是符号位(0为正,1为负),所以表示的最大的正数是01111111=127。所以a和b在赋值的时候就会进行截断,只会赋值的最低的八位。所以:
a=00000001
b=01111111
运算时就会进行整型提升,由于a和b的最高位是0,所以在a和b的高位补0:
a=00000000 00000000 00000000 00000001
b=00000000 00000000 00000000 01111111
运算结果为00000000 00000000 00000000 10000000
由于c为char类型,会发生截断,只会取低八位:
c=10000000
c的的最高位为1,所以会c的整型提升操作是在c的高位补1,如下:
c=11111111 11111111 11111111 10000000(补码)
然后转化为原码:
c=10000000 00000000 00000000 10000000(原码)
此时c的最高位为符号位,为1,即是负数,10000000=128,所以结果会输出-128。
整型提升是C语言中的隐式类型转换,C语言中还包括其他的类型转换,下面是另外的一种隐式类型转换:
下面是另外的一道例题:
#include <stdio.h>
int main() {
int n = 4;
n -= 5;
if (n > sizeof(n))
printf("1\n");
if (n < sizeof(n))
printf("2\n");
return 0;
}
如果没有心机的看,n-=5后n应该等于-1,而sizeof(n)应该等于4,按理说应该输出1,但是结果如下:
是不是突然觉得发现C的bug了,其实不然,这就是C中整型提升不知道坑了多少人的实例。
现在就讲解一下为什么会得到输出1的:
在本环境中中int 默认是signed int(不同编译环境下默认是不同的)
-1=11111111 11111111 11111111 11111111(补码,最高位是符号位)
由于sizeof()的返回值是size_t,是unsigned int类型的数
此时C中有一个原则:小的往大的扩展。标准转换的规则是:短的的向长的转;有符号的向无符号的转。所以在n和sizeof(n)进行比较的时候会将n的signed int转化为unsigned int 类型,此时n的最高位就不再是符号位而是数值位,所以此时c=4294967295,这个数会远远大于4或8。所以输出结果是1。