1.运算符?
是用来进行某种运算的符号
几目运算符? 这个运算符需要几个操作数就称为几目
单目运算符
双目运算符
三目运算符
结合性 :从左至右 从右至左
当两个运算符的优先级是一样的,看结合性
优先级 :单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 条件运算符 > 赋值运算符 > 逗号运算符
(1)算术运算符
++ -- :单目运算符
* / % + - :双目运算符 ,结合性从左至右,先乘除后加减
eg:
5/4 =》 1 (整数进行算术运算其结果为整数)
5.0/4 => 1.25
double(3/2) =》1.0
(double)3/2 =》1.5
% :求余 ,要求两个操作数都必须为整数
5%4 =>1
4%5 =>4
用C语言的表达描述数学表达式 a/b => a*1.0/b
a+b 与 b+a 在C语言中含义是不一样的
i = 5,j = 6;
(i++) +(i+j) =>17
(i+j)+(i++) =>16
======================
表达式的值 做完表达式后i的值
i++ i i = i+1
++i i+1 i = i+1
i-- i i = i-1
--i i-1 i = i-1
eg:
i = 5;
a = i++;//把表达式(i++)的值赋值给a,i++这个表达式的值为5
a = (++i);
NOTE:
++ -- 隐含了 “赋值”
i = i+1;
i = i-1;
so :
(i+j)++ =>error
(1+2)++ =>error
i++ ; =>i必须要是一个变量
(2)关系运算符:用来判断两个东西的关系的运算符
< <= > >=
== !=
双目运算符, 从左至右
关系表达式 :用关系运算符连接起来的式子
关系表达式的值 : “关系成立 (1)” “关系不成立(0)”
eg:
5 > 4 =>1
3 <= 4 =>1
5 > 4 > 3 这是一个合法的表达式
5 > 4 > 3 =》(5>4)>3
=>1>3
=>0
数学上的5 > 4 > 3 与C语言中的含义是不一样的
如何描述我们数学上的5 > 4 > 3 ?
5 >4 并且 4 > 3
(3)逻辑运算符
! 逻辑非 单目运算符 取反
&& 逻辑与 双目运算符 从左至右 “并且”
|| 逻辑或 双目运算符 从左至右 “或者”
逻辑表达式 :用逻辑运算符连接起来的式子
逻辑表达式的值 :逻辑真(非0,1) 逻辑假(0)
&& :左右两边结果都为真 =》真
|| :左右两边只要有一者为真 =》真
eg:
a = 4,b = 5
a && b =>1
a || b =>1
!a|| b =>1
5 > 3 && 8 < 4-!0
=>1 && 0 =>0
练习:
int a = 1,b = 2,c = 3,d = 4,m = 1,n = 1;
(m = a > b) && (n = c > d);
printf("%d %d %d %d %d %d ",a,b,c,d,m,n);
=>1 2 3 4 0 1
// m = 0 n = 1
C语言运算符的“惰性运算”
(1) a && b && c
只有a为真,才需要判断b的值
只有a和b都为真,才需要判断c的值
(2)a || b || c
只要a为真,就不需要判断b和c的值
只有a为假,才需要判断b的值
只有a和b都为假,才需要判断c的值
(4)位运算符
位运算符是按照bit为来进行计算运算
& 按位与
| 按位或
^ 按位异或
~ 按位取反
<< 按位左移
>> 按位右移
除了~是单目运算符,其余都是双目运算符,结合性都是从左至右
位运算的操作数只能是整数(int/short/long/char)
所有的位运算都需要把操作数变成bit位序列,然后在进行操作
~ (按位取反) 单目运算符
0 ->1
1 ->0
int a = ~3;
printf("%d ",a);//-4
printf("%u ",a);//2^32-4
~3:
00000000 00000000 00000000 00000011
11111111 11111111 11111111 11111100
%d:
11111111 11111111 11111111 11111011 (-1)
00000000 00000000 00000000 00000100
%d =>-4
%u:
11111111 11111111 11111111 11111100
%u =>2^32-1-3
===========
int a = ~(-3);
printf("%d ",a);//2
printf("%u ",a);//2
-3 :
00000000 00000000 00000000 00000011 (3)
11111111 11111111 11111111 11111100 (取反)
11111111 11111111 11111111 11111101 (+1)
~(-3) 00000000 00000000 00000000 00000010
%d :
00000000 00000000 00000000 00000010
%u :
00000000 00000000 00000000 00000010
-3+4:
//==================================
& (按位与) :双目运算符 “与”
a b a&b
1 1 1
1 0 0
0 1 0
0 0 0
& :如果两个bit位操作数都为1 ,结果才为1
否则为0
eg :
3 & 5 == ?
00000011
00000101
& 00000001
假设有一个整型变量a.要把a的第5bit变为0,其他bit位不变,该如何操作?
a :xxxx....Xxxxxx
& :1111....011111 ~(1<<5) 00000000 00000000 00000000 00100000
a = a & ~(1<<5)
与1&为原值,与0|为原值
结论:
一个bit位与0进行“按位与”,其结果为0
x & 0 == 0
一个bit位与1进行“按位与”,其结果保留原值
x & 1 == x
(-3)&(-5) =>
-3 :11111101
-5 :11111011
& :11111001
//==========================
| (按位或) :双目运算符, 结合性从左至右
a b a|b
1 1 1
1 0 1
0 1 1
0 0 0
按位或,只有有一个bit操作数为1,其结果为1
假设有一个整型变量a.要把a的第5bit变为置1,其他bit位不变,该如何操作?
a :xxxx....Xxxxxx
| :0000....100000 (1 << 5)
a = a | (1<<5)
(-3)&(-5) =>-1
结论:
一个bit位与0进行“按位或”,其结果保留原值
x | 0 == x
一个bit位与1进行“按位或”,其结果为1
x | 1 == 1
//=======================
^ (按位异或) 双目运算符 “异或” 不同为1 相同为0
a b a^b
1 1 0
1 0 1
0 1 1
0 0 0
练习:
(-3)^(-5) =>6
假设有一个整型变量a.要把a的第5bit变为置1,其他bit位取反,该如何操作?
a = (a|(1<<5))^(~(1<<5))
假设有一个整型变量a.要把a的第5bit变为保留,其他bit位取反,该如何操作?
a :xxxx....Xxxxxx
^ :1111....011111
a = a^(~(1<<5))
结论:
一个bit位与0进行“按位异或”,其结果保留原值
x ^ 0 == x
一个bit位与1进行“按位异或”,其结果取反
x ^ 1 == ~x
//========================================
<< (按位左移) 双目运算符 将bit位整体往左边移
a << n 把a按bit位整体左移n位
高位左移后,丢弃,低位补0
如果左移后丢弃的高位全部为0 ,那么左移n位,就表示原值乘以2的n次方
1 << 5
>> (按位右移) : 双目运算符 将bit位整体往右边移
x >> n 把x按bit位整体右移n位
低位右移后,舍弃 ,高位?
有符号数 :高位全部补符号位
无符号数 :高位全部补0
int a = -1; //1111111 11111111 11111111 11111111
a = a >> 31;
printf("%d ",a);//-1
======
unsigned int a = -1;//
a = a >> 31;//00000000 00000000 00000000 00000001
printf("%d ",a);//1
(5) 条件运算符
?= 三目运算符
expression1 ? expression2 : expression3
上面是一个条件表达式:
如果expression1的值为真,则整个条件表达式的值为expression2这个表达式的值
如果expression1的值为假,则整个条件表达式的值为expression3这个表达式的值
eg:
a = 5>4 ? 4 :3;
(6)赋值运算符 双目运算符 ,从右至左
=
a = 5+3;// 赋值运算符的左边必须是一个可写的地址(左值)
赋值表达式 :有赋值运算符连接起来的式子
赋值表达式的值就是最后赋值后左边变量的那个值
a = 6;
b = a = 5;//合法
复合的赋值运算符:赋值运算符和算术运算符,位运算符组成的复合的运算符
+= -= %= *= /=
<<= >>= |= &= ^=
a += 1 =》a = a+1
a += 5+6 => a = a +(5+6)
(7) 逗号运算符: 双目运算符 优先级最低 从左至右
表达式1,表达式2
逗号表达式的求值顺序 :
先求表达式1的值,然后再求表达式2的值
整个表达式的值是表达式2的值
int a = 5,b = 6;
a = (a=6,a+b); =>12
逗号表达式值扩展:
表达式1,表达式2,....表达式n
求值顺序 :
先求表达式1的值,然后再求表达式2的值,再求表达式3的值
....一直求导表达式n的值
整个表达式的值是表达式n的值
(8)指针运算符
*(指向) &(取地址符)
(9)求字节运算符 (sizeof)
sizeof() :运算时只看括号内是什么数据类型,单位是字节
sizeof(1) =>4
sizeof(1.0) =>8
int a;
sizeof(a+1) =>4
sizeof(a+1.0) =>8
printf("%d ",sizeof(1.0));
(10) 分量运算符
用来求结构体变量的成员变量
.
->
(11)下标运算符
[] :用来求取数组元素
int a[10];//定义了一个数组,数组名a,里面有10个int元素
a[0]
(12)强制类型转换运算符
(类型)值
float f = 3.6;
(int)f +3.5 => 6.5
(int)(f+3.5) =>7
(13)其他
函数调用运算符
2.表达式
表达某个意思的式子
在C语言中一般是用运算符连接操作数的式子,叫表达式
是表达式就有一个值 =》表达式的值 =》表达式值类型
作业:
答案
第一题(x>>p)& ((1<<n) - 1)
第二题 上题取出来| (y & ( ~0 << n))
第三题 x ^ ( ( ( 1 << n ) - 1 ) << p )
第四题 (x & ( ( 1 << n) - 1) << (sizeof(x) * 8 - n) ) | x>>n
第二次尝试:
1.取x中第p位开始的n个bit位
//先将x左移p是可以的,4个1,依次左移1,相与
//大哥的思路 (x>>p)&(~(-1<<n))
2.将x中第p位开始的n个bit位设置为y中最右边的n位的值
x的其余位不变
//用000111000这种的取到n之后的数值,再进行右移p位
//自己感觉,用~(-1)进行取到所有的X,之后直接右移P位,但不知道会不会破坏原来的//数值 (x&(~(-1)))>>p ((x>>p)&(~(-1<<n)))|(y<<n)
3.将x中第p位开始的n个bit位取反,其余位不变
//异或001100这种字符串
//反正都是用-1,想到先右移p,再左移p,再全部相异或 x^(((-1)>>p)<<p)
4.将x循环右移n位
//还是用-1进行处理,((x | (-1) << n) << (long - n) ) | (x >> n)
5.
分析以下程序的输出结果
char c = -56 >> 30;
printf("%d ",c);
printf("%u ",c);
========
char c = -56u >> 30;
printf("%d ",c);
printf("%u ",c);
第一次尝试:
// 1.取x中第p位开始的n个bit位
//1<<(p + 1)..1<<(p + n) 每个与P进行按位与 ,最后叠加也进行与就好 再合并就好应该来说。。
// 2.将x中第p位开始的n个bit位设置为y中最右边的n位的值
// x的其余位不变
//逆运算
// 3.将x中第p位开始的n个bit位取反,其余位不变
//将n左移之后异或
// 4.将x循环右移n位
//取第一位,全体左移,替换最后一位
// 5.
// 分析以下程序的输出结果
// char c = -56 >> 30;
//-56补码 24个1 1100 0111 右移30位后 32个1 再取8位
// printf("%d ",c);
//补码8个1,所以得到答案 -1与255
// printf("%u ",c);2^32 - 1
// ========
// char c = -56u >> 30;
//-56补码 24个0 1100 0111 右移30位后 32个1 再取8位
// printf("%d ",c);右移后全为0 3 3 结果
// printf("%u ",c);
运算符优先级
优先级 |
运算符 |
名称或含义 |
使用形式 |
结合方向 |
说明 |
1 |
[] |
数组下标 |
数组名[整型表达式] |
左到右 |
|
() |
圆括号 |
(表达式)/函数名(形参表) |
|
||
. |
成员选择(对象) |
对象.成员名 |
|
||
-> |
成员选择(指针) |
对象指针->成员名 |
|
||
2 |
- |
负号运算符 |
-算术类型表达式 |
右到左 |
单目运算符 |
(type) |
强制类型转换 |
(纯量数据类型)纯量表达式 |
|
||
++ |
自增运算符 |
++纯量类型可修改左值表达式 |
单目运算符 |
||
-- |
自减运算符 |
--纯量类型可修改左值表达式 |
单目运算符 |
||
* |
取值运算符 |
*指针类型表达式 |
单目运算符 |
||
& |
取地址运算符 |
&表达式 |
单目运算符 |
||
! |
逻辑非运算符 |
!纯量类型表达式 |
单目运算符 |
||
~ |
按位取反运算符 |
~整型表达式 |
单目运算符 |
||
sizeof |
长度运算符 |
sizeof 表达式 sizeof(类型) |
|
||
3 |
/ |
除 |
表达式/表达式 |
左到右 |
双目运算符 |
* |
乘 |
表达式*表达式 |
双目运算符 |
||
% |
余数(取模) |
整型表达式%整型表达式 |
双目运算符 |
||
4 |
+ |
加 |
表达式+表达式 |
左到右 |
双目运算符 |
- |
减 |
表达式-表达式 |
双目运算符 |
||
5 |
<< |
左移 |
整型表达式<<整型表达式 |
左到右 |
双目运算符 |
>> |
右移 |
整型表达式>>整型表达式 |
双目运算符 |
||
6 |
> |
大于 |
表达式>表达式 |
左到右 |
双目运算符 |
>= |
大于等于 |
表达式>=表达式 |
双目运算符 |
||
< |
小于 |
表达式<表达式 |
双目运算符 |
||
<= |
小于等于 |
表达式<=表达式 |
双目运算符 |
||
7 |
== |
等于 |
表达式==表达式 |
左到右 |
双目运算符 |
!= |
不等于 |
表达式!= 表达式 |
双目运算符 |
||
8 |
& |
按位与 |
整型表达式&整型表达式 |
左到右 |
双目运算符 |
9 |
^ |
按位异或 |
整型表达式^整型表达式 |
左到右 |
双目运算符 |
10 |
| |
按位或 |
整型表达式|整型表达式 |
左到右 |
双目运算符 |
11 |
&& |
逻辑与 |
表达式&&表达式 |
左到右 |
双目运算符 |
12 |
|| |
逻辑或 |
表达式||表达式 |
左到右 |
双目运算符 |
13 |
?: |
条件运算符 |
表达式1? 表达式2: 表达式3 |
右到左 |
三目运算符 |
14 |
= |
赋值运算符 |
可修改左值表达式=表达式 |
右到左 |
|
/= |
除后赋值 |
可修改左值表达式/=表达式 |
|
||
*= |
乘后赋值 |
可修改左值表达式*=表达式 |
|
||
%= |
取模后赋值 |
可修改左值表达式%=表达式 |
|
||
+= |
加后赋值 |
可修改左值表达式+=表达式 |
|
||
-= |
减后赋值 |
可修改左值表达式-=表达式 |
|
||
<<= |
左移后赋值 |
可修改左值表达式<<=表达式 |
|
||
>>= |
右移后赋值 |
可修改左值表达式>>=表达式 |
|
||
&= |
按位与后赋值 |
可修改左值表达式&=表达式 |
|
||
^= |
按位异或后赋值 |
可修改左值表达式^=表达式 |
|
||
|= |
按位或后赋值 |
可修改左值表达式|=表达式 |
|
||
15 |
, |
逗号运算符 |
表达式,表达式,… |
左到右 |
从左向右顺序结合 |
|
|
|
|
|
作业答案
1.取x中第p位开始的n个bit位
(x >> p)&((1<<n)-1)
2.将x中第p位开始的n个bit位设置为y中最右边的n位的值
x的其余位不变
((x>>p)&((1<<n)-1) )|(y&(~0<<n))
3.将x中第p位开始的n个bit位取反,其余位不变
x^(((1<<n)-1)<<p)
4.将x循环右移n位
(x&((1<<n)-1) <<(sizeof(x)*8-n)) | x >>n
5.
分析以下程序的输出结果
char c = -56 >> 30;
printf("%d ",c);//-1
printf("%u ",c);//2^32-1
-56的补码;
11001000
11111111
========
char c = -56u >> 30;
printf("%d ",c);//3
printf("%u ",c);//3
unsigned int : -56u
补码:
00000000 00000000 00000000 00111000 (56)
11111111 11111111 11111111 11000111 (取反)
11111111 11111111 11111111 11001000 (-56的补码)
00000000 00000000 00000000 00000011 >> 30
int =>char
00000011
char =>int