在上一文章中我们已经学习了大部分关于操作符的知识,我们这篇文章将剩下的内容学习完,大家可以先复习一下上一文章的内容。
目录
1.操作符的属性:优先级、结合性
1.1优先级
操作符的优先级指的是在一个表达式当中如果包含了多个操作符,那么操作符执行的顺序是不一样的。比如我们先看下面这个例子:
6 + 7 * 9;
1.2结合性
当两个或以上操作符优先级相同时,再计算这个表达式的时候我们就需要用到结合性,即相同优先级操作符从左往右或是从右往左进行计算,但是大部分都是从左向右执行的,如:
5 * 6 / 2;
对于这个表达式,由于乘法操作符(*)和除法操作符(/)的优先级是一样的,所以我们根据结合性从左到右计算这个表达式的值,即先计算5*6,再计算/6。
![](https://img-blog.csdnimg.cn/direct/58204736973e49ea8f4a5f8df10260ff.png)
我们不需要将上面表格中的内容全记下来,当然这也不现实,我们只需要熟悉常见的几个,当有需要的时候再来查表就行了。在我们遇到不确定的时候,还可以直接加括号()不就行了,多省时对吧。
2.表达式求值
在对表达式求值时,只有优先级和结合性有时候也是不够用的,这个时候就需要运用到整型提升和算数转换了。
2.1整型提升
当字符或短整型数字进行运算时,首先至少要转换成int或unsigned int类型才能继续计算,这种转换称为整型提升,原因是因为表达式的整型运算要在CPU的相应运算器件内执行,CPU内的整型运算器的操作数的字节长度一般是int 类型的字节长度,即四个字节。比如下面这个例子:
int main()
{
char a = 3;
char b = 127;
char c = a + b;
return 0;
}
a和b首先进行整型提升,再进行计算。
那如何进行整型提升呢?
Rule 1:有符号整数进行整型提升,按照变量的数据类型的符号位进行提升。
Rule 2:无符号整数进行整型提升,高位补0。
我们对上述代码进行解析:
//整型提升
#include <stdio.h>
int main()
{
char a = 3;//char -- unsigned char
//0 - 24个0 - 0000011
//00000011 - a
char b = 127;
//0 - 24个0 - 1111111
//01111111 - b
char c = a + b;
//0 - 25个0 - 00000011
//0 - 25个0 - 01111111
//0 - 25个0 - 10000010
//10000010 - c
//
//1 - 25个1 - 10000010 - c提升后的结果
//1 - 25个0 - 01111110 - 原码
printf("%d\n", c);
return 0;
}
数字3的补码为:0 - 24个0 - 0000011 , 将数字3赋值给a时,因为a的类型为char类型即只有一个字节,所以a中只能储存一个字节即8个比特位,所以需要进行截断只保留最后的8个比特位,所以此时a中储存的比特位为:00000011
数字127的补码为:0 - 24个0 - 1111111, 同理也因为char类型发生截断,截断后b中储存的比特位为: 01111111
在执行 a+b 时先对8比特位的a,b进行整型提升,因为都为char 类型所以为有符号位,提升时,补由于符号位是0,所以在a,b前面补0即可,补够32位。
提升将两者的补码进行相加:
0 - 24个0 - 0000011
0 - 24个0 - 1111111
将a和b的补码进行相加后得到的补码为:
0 - 25个0 - 10000010
但是有因为c也是char类型, 所以依然发生截断,截断后c中存储的比特位为:10000010
然而,printf中打印以c是%d的形式打印,即还需要将c提升为32个比特位,即1 - 25个1 - 10000010,再将补码取反+1转化为原码1 - 25个0 - 01111110 ,最后转为10进制得到c的结果其实为-126。
整个过程稍有些复杂,大家可以多看几遍。
2.2算数转换
如果对于一个操作符,他的两个操作数不是同一类型,如int+double,那么就会将其中一个类型转换成另外一种类型,如上述将int转换成double再进行求值。以下体系称之为寻常算数转换:
1 long double
2 double
3 float
4 unsigned long int
5 long int
6 unsigned int
7 int