一、表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。同样,有些表达式的操作数在求值过程中可能需要转换为其他类型。
int main()
{
int a = 3;
int b = 5;
int c = a + b * 7;//先执行b*7
return 0;
}
二、隐式类型转换
C的整型算数运算总是至少以缺省(shěng)值类型的精度来进行的。为了获得这个精度,表达式中的字符char
和短整型short
操作数在使用之前被转换成为普通整型int
,这种转换称为整型提升。
实例①
char a, b, c;
//···
a = b + c;
a,b,c是char
类型,在内存中占据1个字节没有达到一个普通整型int
的大小(4个字节)。在计算a = b + c
时,我们需要把b和c的值提升为普通整型int
,变成4个字节,然后再执行加法运算。加法运算完成后,我们发现b+c的结果是4个字节,而a是1个字节,a中放不下计算结果,所以结果将被截断,然后在存储于a中。
截断:在本题中我们将4个字节的数据存放到1个字节中,我们只保留最低的那个字节中的内容,把剩余的3个字节中的内容扔掉。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内运行,CPU内整型运算器(ALU)的操作数的字节长度一般是int
的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int
或者unsigned int
,然后才能送入CPU去执行运算。
也就是说在运算时,不管是char
类型还是short
类型都没有达到一个int
类型的大小,但是CPU又是以整型的方式来计算的。此时若我们把char
和short
提升为整型int
,那么计算精度会高一些。(不转白不转,不升白不升)
1.整型如何提升?
实例②
int main()
{
char a = 3; //二进制序列:00000000000000000000000000000011
char b = 127;//二进制序列:00000000000000000000000001111111
char c = a + b ;
//发现a和b都是char类型,都没有达到一个int的大小
//这里就会发生整型提升
printf("%d\n", c);
return 0;
}
运算结果:
首先,我们发现a和b是char类型,我们把3放到a里,127放到b里,a+b的结果放到c里。数据在内存中以补码的形式存储,正数的原码、反码和补码是一样的,负数的原码、反码和补码是互不相同的。
(1)原码: 将数字转换成二进制,并在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。
(2)反码: 将原码符号位不变,其他位依次按位取反。
(3)补码: 符号位不变,反码加一得到补码。
然后,3的二进制序列是:00000000000000000000000000000011
127的二进制序列是:00000000000000000000000001111111
我们把3的二进制序列放到a中,而a是一个char类型,只能放8个比特位,所以会发生截断,只存储最小的8个比特位,即:00000011
同理:b也只能存储最小的8个比特位,即:01111111。27是128(二进制:10000000),所以127是01111111。
此时a+b
就是00000011+01111111,而这两个都是char类型,没有达到int类型的大小,所以这里就会发生整型提升。
整型提升是按照变量的数据类型的符号位来提升的。
我们让a发生整型提升,a是char类型,char是有符号的char。所以这8个bit位的最高位是符号位,而a和b的符号位都是0,表明他们都是正数,整型提升时高位补的都是0。
提升完后:
a的二进制序列:00000000000000000000000000000011
b的二进制序列:00000000000000000000000001111111
相加结果为:00000000000000000000000010000010
(1)a和b的二进制序列最末位的都是1,1+1=2,余0进1,则结果的二进制序列最后一位为0。
(2)进1后,倒数第二位上是1+1+1=3,余1进1,则结果的二进制序列倒数第二位为1。
(3)进上来的1和a、b的二进制序列的倒数第三位上的0和1相加,1+1+0=2,余0进1。以此类推,直至倒数第8位,此时为1+0+0=1,所以余1。再往前a和b的二进制序列对应位的相加结果均为0。
加完之后的二进制序列00000000000000000000000010000010
要放到c里面去,而c是一个char类型,所以只能放最小的8个比特位,即10000010。
此时的a、b、c的二进制序列分别是:
名称 | 二进制序列 |
a | 00000011 |
b | 01111111 |
c | 10000010 |
c是char类型,但printf("%d\n", c);
它是以整型打印的,所以c也需要进行整型提升。
c整型提升后:11111111111111111111111110000010
(补码),内存中的数字用补码计算。符号位是1,则代表c是负数。打印出来,我们看到的数字应该是原码。
原码取反,+1是补码;补码-1取反是原码11111111111111111111111110000010
——补码11111111111111111111111110000001
——反码10000000000000000000000001111110
——原码
26+25+24+23+22+21
=64+32+16+8+4+2
=126,前面的符号位是1,则c为-126。
2.整型提升总结
(1)负数的整型提升
二进制序列是补码,高位补充符号位,即为1
(2)正数的整型提升
原、反、补均可,高位补充符号位,即为0
(3)无符号整型提升
如:unsigned char,unsigned short两种类型是无符号的,高位补0