关于操作符之前简单介绍过一点,这篇详细介绍C语言中的操作符的使用和一些细节
目录
1.算数操作符
2.移位操作符
2.1移位操作符基础
2.2移位操作符移动
3.位操作符
4.赋值操作符
5.单目操作符
6.关系操作符
7.逻辑操作符
8.条件操作符
9.逗号表达式
10.结构成员访问操作符
11.操作符的属性
12.表达式的求值
12.1整型提升
12.2算数转换
1.算数操作符
包括四则运算(+、-、*、/)和取模操作符(%)
算数操作符中需要注意的有一下几点:
1.操作符%只能用于整数运算
2.操作符/要进行浮点数运算,那么除数和被除数至少有一个为浮点数
2.移位操作符
2.1移位操作符基础
位指的是二进制位,是数据在内存中存储的方式
移位有左移(<<)和右移(>>),移位操作符的操作数只能是整数
之前的文章介绍过整数在内存存储的二进制的表示形式,这里作一个简单概括:
整数有3种二进制表示形式,分别是原码、反码和补码,整数在内存中以补码的形式存储,在打印时以原码打印,二进制最高位为符号位,符号位为1表示负数
对于非负整数来说,三者是相同的
对于负整数来说,原码最高位不变,其它位按位取反得反码,反码+1得补码
那么现在有个问题,我们将二进制位移动后,缺失的部分是如何填充的?
2.2移位操作符移动
先来看操作符<<
可以看出,当i左移一位之后,低位补的是0,这便是左移操作符移位时的规则:左边抛弃,右边补0
接着是操作符>>
对于右移,其规则有两种
算数右移:右移后左边填充原符号位
逻辑右移:右移后左边填充0
大多数的编译器采用的是算数右移
还有一点要注意:使用移位操作符时不要移动负数位,C语言标准中没有定义这样的写法,到时出现什么情况自己负责
3.位操作符
有按位与(&)、按位或(|)以及按位异或(^),它们的操作数同样只能为整数
位依旧是二进制位
操作符&:a&b,a和b对应的二进制位都为1时结果才为1,否则为0
图中3的二进制位:00000000000000000000000000000011
1的二进制位:00000000000000000000000000000001
3&1的二进制位:00000000000000000000000000000001
故i为1
操作符|:a|b,a和b对应的二进制位中只要有一个为1结果就为1
图中3的二进制位:00000000000000000000000000000011
1的二进制位:00000000000000000000000000000001
3&1的二进制位:00000000000000000000000000000011
i的结果为3
操作符^:a^b,a和b对应二进制位相同结果为0,不同结果为1
图中3的二进制位:00000000000000000000000000000011
1的二进制位:00000000000000000000000000000001
3&1的二进制位:00000000000000000000000000000010
i的结果为2
4.赋值操作符
赋值操作符的内容没有过多需要介绍的地方
a+=1和a=a+1是相同的,其它的符合操作符同理
5.单目操作符
单目操作符中的“&”和“*”在后续指针的时候介绍,这里就略过
- !
逻辑反操作符
- ~
对一个数的二进制位按位取反
- sizeof
求操作数的长度,单位为字节
- ++/--
有前置和后置,效果是给一个数+1/-1,前置是先计算后使用,后置是先使用后计算,详细的区别之前博客中有过介绍,这里不再赘述
- ()
强制类型转换,括号内写入需要转换的数据类型
6.关系操作符
==、!=、>=、<=、>、<
一般用于判断,注意==和=别弄错
7.逻辑操作符
逻辑与(&&)和逻辑或(||)
二者就是数学上的逻辑与和逻辑或,这里主要说说它们运行时候的逻辑
a&&b,若a为假,那么后面的b便不会再判断它的真假,即a为假便停止判断。只有a为真的时候才会继续去判断b
a||b,a为真的时候,同样不会判断b
8.条件操作符
条件?表达式1:表达式2
条件为真执行表达式1,否则执行表达式2
某些情况下可以代替if语句,比如说打印a和b两个整数较大的值
a>b?printf("%d",a):printf("%d",b);
9.逗号表达式
就是用逗号隔开的多个表达式
int a=1;
int b=2;
int c=(++a,++b,5);
printf("%d",c);
先来看c的值
可以看出,c的结果是最后一个表达式的结果,那前面的++a和++b有没有执行?
很明显,++a和++b是被执行过的
所以,逗号表达式从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
10.结构成员访问操作符
访问结构体时使用的操作符(“.”和“->”)
具体在后续结构体中详细介绍
C语言的操作符就介绍到这,感谢观看
11.操作符的属性
介绍了这么多的操作数,那么有一个问题
一个表达式中有多个操作数,那么操作数进行运算的顺序是怎样的?
这由操作数的属性决定
1. 操作符的优先级
2. 操作符的结合性 (即运算是从左往右还是从右至左)
3. 是否控制求值顺序(只有&&、||、逗号表达式和 ? :可以控制求值顺序)
两个相邻的操作符先执行哪个?
这取决于他们的优先级。如果两者的优先级相同,那么就看结合性。
操作符优先级最高的是()
但即使操作符有这些属性,很多时候表达式的值还是不唯一
a*b+c*d+e*f
上述表达式*的优先级比+高,所以先计算a*b和c*d,那第三步呢?是计算e*f还是计算a*b+c*d,此时优先级并不能决定,也就是说这个表达式的运算路径不是唯一的,那么不同编译器因为运算的路径不一样就会产生不同的结果,所以在写表达式时要保证计算路径的唯一,如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的
12.表达式的求值
不同数据类型的操作数求值时可能需要转换为其他类型。
12.1整型提升
针对char和short的计算
char a=1; char b=2; char c=a+b;
在执行运算时a和b要提升为int才可以计算
因为表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度,同时也是CPU的通用寄存器的长度。通用CPU是难以直接实现两个8比特字节直接相加运算,所以,表达式中各种长度可能小于int长度的整型值,都必须先转 换为int或unsigned int,然后才能送入CPU去执行运算。
a和b提升至int后算出来结果为3,此时3位int型,而c是char型,所以3要放入c中的话,需要进行截断,3的32位二进制位c只取低位的8位
12.2算数转换
整数和浮点数进行计算
int a=3; float b=1.5; float c=a+b;
如果想要正常进行运算,a要转换成float型之后才可以进行后续的计算
double
float
unsigned long
long
unsigned int
int
上述排在下方的操作数,和其它操作数运算时首先进行转换
完



