携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情
小试牛刀
//复杂表达式求值案例一
#include<stdio.h>
int mian()
{
int i=1;
int c= (++i) + (i++) + (i++);
printf("C=%d",c);
return 0;
}
//复杂表达式求值案例二
int fun()
{
static int i=1;
i++;
return i;
}
#include<stdio.h>
int main()
{
int sum=fun()+fun()+fun();
printf("sum=%d",sum);
return 0;
}
看了上面的案例,是不是发现有你学校老师出题那味了,你是否被学校的这种题目给恶心到过! 首先恭喜你,今天bug郭就带你吊打这类智障题目!
表达式求值
啥是表达式求值呢? 通俗的说就是,像我们加减乘除算数运算一样,通过计算求得运算结果,而C语言不止加减乘除运算,所有的C语言操作符,计算而得出结果,这就是表达式求值! 表达式求值的顺序 我们已经知道,表达式求值就是操作符运算的结果。像加减乘除都有自己的运算顺序,所以操作符都有自己的运算顺序。 而我们知道C语言有很多操作符,每个操作符的优先级,和结合性又不一样!
表达式求值的顺序一部分是由操作符的优先级和结合性决定。 同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
隐式类型转换
什么是隐式类型类型转换 我们C语言中的数据类型很多,当不同类型的数据进行运算时,某一类数据,就会进行类型转换而后进行运算。 C语言中的隐式类型转换规则
C语言中的整型算术运算总是至少以缺省整型类型的精度来进行的。 为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为
整型提升。
有人就该疑惑了,为啥C语言中要以整型的精度进行计算呢,为啥不能是浮点型? 整型提升的意义:
表达式的整型运算要在
CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
我们可以知道计算机中CPU中运算器的运算标准就是整型(int)进行运算,所以当数据类型不足一个整型,计算机会现将该数据进行整型提升,统一成整型,然后送入CPU执行运算!
我们来看看如何进行整型提升
//实例一
char a,b,c;
a=3;
//3 00000000 00000000 00000000 00000011
//a=3; 00000011 char 只能存8个二进制位
//整型3截断后放入a中
b=2;
//2 00000000 00000000 00000000 00000010
//b=2; 00000010 char 只能存8个二进制位,
//整型2截断后放入b中
c=a+b;
//c=a+b;进行运算需要CPU运算器(ALU)
//a和b不足一个整型,需要进行整型提升!
// char a =3;提升后
//3 00000000 00000000 00000000 00000011
//char b=2;提升后
//2 00000000 00000000 00000000 00000010
//a+b
//5 00000000 00000000 00000000 00000101
//将5存入char c中,进行截断 后 c 00000101
printf("c=%d",c);//最后进行%d(整型)打印时
//又将进行一次整型提升 5
//00000000 00000000 00000000 00000101
看到就短短一行代码,计算机却进行了这么多计算。这就是整型提升的步骤,看来表达式求值不易,计算机都这么麻烦,何况我们。
其实并不难的只要我们掌握了整型提升的规律,这都小菜一碟。
整型提升规则
整形提升是按照变量的数据类型符号位进行提升的 1.
有符号数据类型,整型提升补符号位2.无符号数据类型,整型提升补0
//实例二
char a = -1;
//-1 原码:10000000 00000000 00000000 00000001
// 补码;11111111 11111111 11111111 11111111
// 截断a=-1 11111111
unsigned char b = 1;
// 1 原码补码相同
// 00000000 00000000 00000000 00000001
//截断 b=1; 00000001
char c = a + b;
// char a 11111111 有符号字符型 符号位提升
// 11111111 11111111 11111111 11111111
//unsigned char b 00000001 无符号字符型 补0提升
//00000000 00000000 00000000 00000001
//a+b
//00000000 00000000 00000000 00000000
// char c 截断 00000000
printf("%d",c);
//有符号的形式打印,进行整型提升后
//00000000 00000000 00000000 00000000
看到这里,你肯定会想,这提升了个锤子,这不就是,1+(-1)=0嘛还用得了这么麻烦?
我们看看下面代码你就知道了整型提升的意义
int main()
{
char a=0xb6;
short b=0xb600;
int c=0xb6000000;
if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");
return 0;
}
打印结果
c
是不是有点出乎意料!
让我一步一步给你分析
int main()
{
char a=0xb6;
// 0xb6 00000000 00000000 00000000 10110110
//截断放入a中 a 10110110
short b=0xb600;
//0xb600 00000000 00000000 10110110 00000000
//截断放入b中 b 10110110 00000000
int c=0xb6000000;
//00000000 00000000 00000000 0xb6000000 存入C中
if(a==0xb6)
printf("a");
//a:10110110 符号位是1 提升
// 11111111 11111111 11111111 10110110
// 转换成原码:
//00000000 00000000 00000000 01001010
//而0xb6
// 00000000 00000000 00000000 10110110
//显然a!=0xb6;
if(b==0xb600)
printf("b");
//b :10110110 00000000 符号位是1提升后
//11111111 11111111 10110110 00000000
//原码:
//00000000 00000000 01001010 00000000
//而0xb600
//00000000 00000000 10110110 00000000
//b!=0xb600
if(c==0xb6000000)
printf("c");
return 0;
整型提升要点总结:
- 计算机中是以数据的补码存储计算的,都是在补码的基础上继续整型提升和计算
- 整型提升补充的二进制位是要看该数据类型是有符号类型,还是无符号类型。
有符号类型补充符号位,也就是该数据的最左边的二进制位
无符号类型同一补充
0 - 当一个数据进行有符号类型打印
%d直接补充该数据的符号位,然后,将该数据转换成原码就是打印的结果 无符号打印时%u直接补充0然后该数据的原反补码相同。