第五节操作符
一、 操作符
操作符分为以下几种操作符:
1、 算数操作符
+、-、*、/、%。
%操作符的两个操作数必须都得是整数,如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
当想计算出一个浮点数结果的时候,就是3/2想计算出1.5的话,就需要让3.0/2或3/2.0。
2、 移位操作符
>>(右移)、<<(左移)
移位操作符是对数字的二进制数进行操作。
二进制数整数与负数又有所不同,正数二进制的原码、反码、补码相同,而负数二进制数的原码、反码、补码是不同的是需要通过计算相互转换的。
如:5的二进制数为:00000000000000000000000000000101。
5是正数,原反补码相同。
-5的二进制数为:10000000000000000000000000000101
负数的原码通过按位取反得到反码,反码末尾+1得到补码。
10000000000000000000000000000101 —> -5的原码
11111111111111111111111111111010 —> -5的反码
11111111111111111111111111111011 —> -5的补码
在内存中存储、操作、计算的都是补码。
例:5<<1——5左移一位的结果是什么?
解析:5的二进制数为:00000000000000000000000000000101
左移操作符是把二进制位向左移动一位,空缺的位置用0填补。
操作如下图:
右移就是把数字的二进制数向右移一位,第一位大多数编译器都采用算数右移。
特别注意:使用位操作符不要移动负数位,这是标准未定义的。
如:int a = 5; a>>-1;//这是笨蛋代码。
3、 位操作符
位操作符有:&按位与、|按位或、^按位异或
注:位操作符的操作数必须是整数。
举例:3和5按位与的结果是?
按位与&的特点是:都为1时才为1,否则就是0。
3:00000000000000000000000000000011
5:00000000000000000000000000000101
3&5 = 00000000000000000000000000000001
举例:3和5按位或的结果是?
按位或|的特点是:只要有1就为1,全为0才是0。
3:00000000000000000000000000000011
5:00000000000000000000000000000101
3|5 = 00000000000000000000000000000111
举例:3和5按位异或的结果是?
按位异或^的特点是:相同为0,不同为1。
3:00000000000000000000000000000011
5:00000000000000000000000000000101
3^5 = 00000000000000000000000000000110
4、 赋值操作符
赋值运算符就是 =,可以把已经有值的变量通过=更改为其他值,
赋值运算符还可以和其他运算符搭配在一起使用。
如:+=、-=、*=、/=、%=、>>=、<<=、&=、|=、^=等等。
5、 单目操作符
单目操作符分为:
!逻辑反操作符就是将真改为假,将假改为真。通常用在选择判断或循环判断中。
-、+就是将常量改为正值或负值。
sizeof操作符:求数组或变量名或常量所占字节的大小。
~操作符是对二进制按位取反,1改为0,0改为1。
--和++前置和后置所得到的结果有时有可能不一样。
前置--,如a=2;b=--a;--在前,先计算a=a-1;在赋值b=1。
后置--,如a=2;b=a--;--在后,先赋值b=2,再计算a=a-1;
++同理。
(类型)是强制类型转换操作符,当表达式计算的结果要赋值到另一个类型中时,我们可以使用强制类型转换,将表达式的类型转变成我们想要的类型。如:int a = (int)3.14159;
和&是一对操作符,这里的代表的是解引用操作符,而&是取地址操作符。如:
这里创建一个指针变量pa用来存放a的地址,对pa使用*操作符,就是对pa进行解引用操作,得到pa指向地址处的值,就是a的值。
6、 关系操作符
关系操作符有:>、<、>=、<=、!=、==。
==是判断两个数字或变量的值是否相等,而=是赋值用的。
7、 逻辑操作符
逻辑操作符有:&&、||
这两个操作符都有中断操作,就是当&&操作符的左边判断为假的时候,右边就不计算了,而当||操作符的左边为真的时候,右边也不计算了。
举个栗子:先看&&
因为,a首先判断为假,而&&操作符是必须得全为真才是真,所以只计算了a,剩下的都没计算。
再看||
因为||操作符是只要有一个真,整体就为真,所以a首先是0为假,继续向后执行,当执行到b,b值是2为真,所以后面的d++就跳过不计算了。
8、 条件操作符
exp1?exp2:exp3;这个操作符与下图是等价的。
当exp1判断为真执行exp2,判断为假,执行exp3。
9、 逗号表达式
(exp1,exp2,exp3,……,expn);
这个操作符会将()内的表达式依次执行到最后,但是返回的结果是最后一个表达式expn的值。
10、 下标引用、函数调用、结构体成员操作符
(1) 下标引用操作符
如:创建数组,找到数组中的某个元素方法为arr[5],其中[]是操作符,而arr和5是这个操作符的操作数。(也可以写成5[arr],他与arr[5]等价。)
(2) 函数调用操作符
如:
函数Add后面的()就是函数调用操作符,这个函数调用操作符的操作数有:Add、x、y三个操作数。
(3) 结构体成员操作符
如下图:
输出结构体时,使用结构体变量名.成员。所以,这个.就是引用结构体成员的操作符。
当这个结构体是指针怎么处理呢?
那就输出结构体的时候使用结构体变量名—>成员。这个就是使用指针对结构体成员引用的操作符。
二、 表达式求值
1、 隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。 为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
整型提升:表达式中各种长度可能小于int长度的整型值,都必须先转 换为int或unsigned int,然后才能送入CPU去执行运算。
举个栗子,如下图:
因为a和b的类型是char类型,又因为赋值的数为整数,所以当赋值到a和b中时,二进制数会发生截断。
a = 00000000000000000000000000000011 ——> 未截断前
a = 00000011 ——> 截断后只会剩下末尾的8个比特位。
b = 00000000000000000000000001111111 ——> 未截断前
b = 01111111 ——> 截断后只会剩下末尾的8个比特位。
a+b的值存放在c中,如图:
但是输出是要以整形输出但是c的类型是char类型,要进行整型提升。整型提升的规则是:整形提升是按照变量的数据类型的符号位来提升的。
c = 10000010 ——> 未整形提升前
c = 11111111111111111111111110000010 ——> 整形提升后
因为在内存中存储和计算的二进制数是补码,输出要以原码输出,所以,将c = 11111111111111111111111110000010,转化为原码后的结果为:-126。
2、 算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
警告: 但是算术转换要合理,要不然会有一些潜在的问题。
3、 符号的优先级
我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。
结尾:感谢你能看到这里,如果有写的不对的地方请给位不吝赐教,谢谢啦!
标签:操作数,二进制,C语言,详解,按位,整型,操作符,表达式 From: https://blog.51cto.com/u_15865089/6342730