嵌入式0基础开始学习 ⅠC语言(2)运算符与表达式
1.运算符
什么是运算符?
用来进来某种运算的符号
如:
+ - * / (取余,取模)
a,几目运算符
根据其操作数的不同
单目运算符
该运算符只需要带一个操作数
如: ++ -- &(取地址符)
双目运算符:
该运算符只需要带两个操作数
如: + - * /
三目运算符:
该运算符需要带三个操作数
如:
a?b:c:
如果表达式a为真,那么整个表达式的值为b,否则整个
表达式的值为c
b,结合性
决定先算谁后算谁问题
从左到右,从右到左
如:
+结合性:从左到右
a+b
先算a的值,再算b的值
最后再算表达式a+表达式b的值
=结合性:从右到左
a=b
先算b的值
再将b的值,写到变量a所对应的存储单元中去
例子:
在c语言中,a+b,是否和b+a的含义一样呢?
不一定,why?
如:
i=5,j=6
(i++)+(i+j) =>5 + 6+6
(i+j)+(i++) =>(5+6)+5
c,优先级
是指在一个含有多个运算符的表达式中,先算哪一个运算符,再算哪一个运算符。
单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 条件运算符 > 赋值运算符 > 逗号运算符
(1)算术运算符
进行算术运算的运算符
+ - * % / :双目运算符,结合性从左到右
例子:
5 /4 => 1(整数进行算术运算结果为整数)
5.0 / 4 =>1.25
typeof(5/4) =>int
typeof(5.0/4)=>double
(double)(3/2) => 1.0
(double)3/2 =>1.5
思考:
用c语言的表达式来描述数学表达式
数学:
a/b
c语言中:
(double)a /b
1.0*a /b
%: 取余,求模
规定,要求两个操作数都必须为整数
5%4 => 1
5%4.0=> ERROR
4%5 =>4
++:
自增运算符
i++//先使用i再++
++i//先++再使用i
--:
自减运算符
i--
--i
单目,要求操作数必须为一个”左值“(可写的地址)
例子:
5++ =>ERROR
(a+b)++ => ERROR
表达式 表达式的值 做完这个表达式之后i的值
i++ i i = i+1
++i i+1 i = i+1
i-- i i = i-1
--i i-1 i = i-1
例子:
(1)int i =5;
a= i++;//把表达式(i++)的值赋值给a,表达式i++的值为5
printf("%d\n",a);//5
printf("%d\n",i);//6
int i =5;
a = ++i;//把表达式(++i)的值赋值给a,表达式++i的值为6
printf("%d\n",a);//6
printf("%d\n",i);//6
(2)i =5;
(i++)+(i++)+(i++)
拒绝做此类题目!!!
因为它没有任何意义
如果老板要你们做这类题目
那就请你将你的BOSS直接炒鱿鱼
(2)关系运算符
用来判断两个东西关系的运算符(大小关系)
< > <= >= == !=
都是属于双目运算符,结合性都是从左到右。
关系表达式:用关系运算符连接的式子。
关系表达式的值:
关系成立 =>1
关系不成立 =>0
例子:
表达式 表达式的值
5>4 1
3<=2 0
0!=1 1
5>4>3 0
5>4>3: 是一个合法的表达式
表达式的含义(5>4)>3
拿表达式5>4的值,与3进行PK
数学含义:
5>4 并且 4>3
问题?
咱们能不能用c语言来描述数学上的5>4>3呢?
涉及到 ”并且“如何来表达?
(3)逻辑运算符
用来描述逻辑关系的运算符
! 逻辑非 单目运算符 ”取反“
!真 =>假
!假 =>真
&& 逻辑与 双目运算符 ”并且“ 结合性从左到右
真&&真 => 真
真&&假 => 假
假&&假 => 假
假&&真 => 假
|| 逻辑或 双目运算符 ”或者“ 结合性从左到右
真||真 => 真
真||假 => 真
假||假 => 假
假||真 => 真
逻辑表达式:就是用逻辑运算符连接起来的式子
逻辑表达式的值:
逻辑真(非0,1)
逻辑假 0
例子:
a = 4, b= 5;
a&&b =>1
a&&0 =>0
(3+5)||(0) => 1
!a || b =>1
4&&0 || 2 =>1
5>3 && 8<4-!0
=>5>3 && 8<4-1
=>5>3 && 8<3
=>1&&0
=> 0
练习:
用逻辑表达式来判断y(输入的年份)是否为闰年
(1)能被4整除,但是不能被100整除
(2)能被400整除
#include <stdio.h>
int main()
{
int a;
printf("请输入年份:");
scanf("%d", &a);
if(a%4==0&&a%100!=0||a%400==0)
{
printf("%d是闰年",a);
}
else
{
printf("%d不是闰年",a);
}
return 0;
}
分析一下代码的输出结构
int a,b,c,d,m,n;
a =1;
b =2;
c =3;
d = 4;
m =0;
n= 0;
(m=a<b)||(n=c<d);
printf("%d\n",m);//1
printf("%d\n",n);//0
(m=a>b)&&(n=c<d);
printf("%d\n",m);//0
printf("%d\n",n);//0
C语言运算符是”惰性运算“
(1)a&&b&&c
只有a为真时,才去判断b的值
只有a,b都为真,才去判断c的值
(2)a||b||c
只要a为真,就不需要再去判断b,c的值
只有a为假,才需要去判断b的值
只有a和b都为假,才需要去判断c的值
如果事先知道表达式的值,那么后面的运算符(表达式)就不需要执行了
,这就是c语言运算符的”惰性“
(4)位运算符
位运算符是指按bit位来进行运算
位运算符要求操作数必须为整数
有如下:
& 按位与
| 按位或
~ 按位取反
^ 按位异或
<< 按位左移
>> 按位右移
除了~是单目之外,其他的位运算符都是双目运算符,结合性都是从左到右
位运算符操作数只能是整数
所有的位运算都是把操作数变成bit序列,然后再按bit位来进行运算
~(按位取反)
1 -> 0
0 -> 1
int a = ~3;
3:
00000000 00000000 00000000 00000011
~3;
11111111 11111111 11111111 11111100 <--a最终再计算机的存储形式
%d:
符号位:
-1
逆运算:
负数:-4
%u: 2^32-4
&(按位与):
a b a&b
1 1 1
0 1 0
1 0 0
0 0 0
& 如果两个bit操作数都为1,其结果才为1,否则为0
例子: int a =3 & 5;
8bits:
0000 0011 (3)
0000 0101 (5)
&----------------
0000 0001 (1)
练习:
写一个表达式
假设有一个整型变量a,要把a的第5个bit变成0,
其他的bit保持不变,该怎么操作?
a:
xxXxxxxx
& 11011111 <= ~(00100000) <= ~(1<<5)
a = a& ~(1<<5);
结论:
一个bit位与0进行”按位与“的操作,结果为0
x&0 => 0
一个bit位与1进行”按位与“的操作,结果为原值
x&1 => x
| 按位或:
a b a|b
0 0 0
0 1 1
1 0 1
1 1 1
| 按位或,只要有一个bit操作数为1,其结果就为1
例子:
int a = 3| 5;
8bits:
0000 0011 (3)
0000 0101 (5)
|------------
0000 0111 (7)
练习;
写一个表达式
有一个整型变量a,要使a的第五位bit置1,其他的bit保持不变
该如何操作?
a:
xxXxxxxx
| 00100000 <= (1<<5)
-----------
a: xx1xxxxx
a = a | (1<<5);
结论:
一个bit位与0进行”按位或“的操作,结果为原值
x|0 => x
一个bit位与1进行”按位或“的操作,结果为1
x|1 => 1
^ 按位异或:
a b a^b
0 0 0
1 0 1
0 1 1
1 1 0
"异或" :求异,不同为1,相同为0
例子:
int a = 2 ^ 32;
8bits:
0000 0010 (2)
0010 0000 (32)
^ ----------
0010 0010 (34)
思考;
有一个整型变量a,要是a的第五位bit保留,其他的全部取反
该如何操作?
a:
xxXxxxxx
11011111
^ ------------
a = a^(~(1<<5))
结论:
一个bit位与0进行”按位异或“的操作,结果为原值
x ^ 0 => x
一个bit位与1进行”按位异或“的操作,结果为原值取反
x ^ 1 => ~x
练习:
写一个程序,交换两个整数的值,不能使用临时变量
int a=6;
int b=5;
int temp;
temp = a;
a = b;
b = temp;
printf(a); //5
printf(b); // 6
----------------------------------
a = a^b;
b = a^b;
a = a^b;
结论:
位运算只与当前位,没有进位,没有有借位
<< 按位左移
a << n 把a按bit序列整体左移n位。
高位左移后,会多出来n个bit位,直接丢弃
低位空出来的n个bit位,直接补0
如果左移后,舍弃的高位都是0(连续的0)
那么左移n位,就表示在原有的基础上,乘以
2的n次方
例子:
8bits:
1 << 4
1: 0000 0001
1<<4: 0001 0000 (1*2^4)
32bits:
7 << 8
7: 00000000 00000000 00000000 00000111
7<<8:00000000 00000000 00000111 00000000(7*2^8)
>> 按位右移
x >> n 把x的bit序列整体往右移n个bits
低位右移后,会多出n位,直接舍弃
高位会空出n位,补什么?
对于有符号的数,高位全部补 符号位!!!!
对于无符号的数,高位直接补0
练习:分析一下代码的输出结果
int a = -1;
-1;
11111111 11111111 11111111 11111111
a = a >> 31;
a >> 31:
11111111 11111111 11111111 11111111
printf("%d\n",a);// -1
printf("%u\n",a);// 2^32 -1
unsigned int a = -1;
-1:
11111111 11111111 11111111 11111111
a = a>> 31;
a >> 31:
00000000 00000000 00000000 00000001
printf("%d\n",a);// 1
printf("%u\n",a);// 1
(5)赋值运算符
= : 双目运算符,结合性从右到左
a = x; 先计算x的值,然后再把x的值,赋值给a
赋值运算符要求左边的操作数 必须为一个”可写的地址“(左值)
例子:
5 = 5; //ERROR
2 + 3 =5;//ERROR
i++ = 6;//ERROR
赋值表达式:由赋值运算符连接起来的式子。
赋值表达式的值:
就是最后赋值给左边变量的那个值
a = b =6;
==>先计算(b = 6)表达式的值,将其表达式的值赋值给a
复合赋值运算符
赋值运算符和算术运算符,位运算符组成的复合的赋值运算符
如:
+= -= %= *= /=
<<= >>= |= &= ^=
例子:
a += 5
=> a = a+5
a += 5 +6
=> a = a+(5+6)
a >>= n
=> a =a>>n
(6)条件运算符
? : 三目运算符
表达式1 ? 表达式2 :表达式3
执行:
如果表达式1的值为真,则整个表达式的值为表达式2的值
如果表达式1的值为假,则整个表达式的值为表达式3的值
例子:
int a,b,c,d,m,n;
a =1;
b =2;
c =3;
d = 4;
m =0;
n= 0;
a>b?(m=a+b):(n=c+d);
printf("%d\n",m);//0
printf("%d\n",n);//7
(7)逗号运算符
双目运算符,优先级是最低,结合性从左到右
表示式1 ,表达式2
执行:
先求表达式1的值,然后再求表达式2的值
整个逗号表达式的值 就是 表达式2的值
例子:
int a=5,b=6;
a = (a = 6,a+b);
a => 12
(8)指针运算符
& ->取地址符
* ->指向运算符
&对象名:
表示的含义是 取某某对象的地址
例子:
int a;
scanf("%d",&a);
(9)sizeof求字节运算符
单目运算符,求一个对象或类型的所占空间的字节数
(10)分量运算符
求结构体中的成员变量(分量)
->
.
(11)下标运算符
[]
数组名 [下标]:表示下标对应的哪一个数组元素
(12)强制类型转换运算符
(类型)
小练习:
1.取整型变量x中的第p位开始的n个bit位
x:
xxxxXXXXxxxx
x >> p :
xxxxxxxxXXXX
000000001111 < = (1<<n)-1
& ------------
00000000XXXX
x=(x>>p)&((1<<n)-1)
2.将x中第p位开始的n个bit全部取反,其余各个位保持不变
x:
xxxxXXXXxxxx
000011110000 <= ((1<<n)-1) << p
^------------
xxxx~(XXXX)xxxx
x = x^((1<<n)-1) << p
3.将x中第p位开始的n个bit位设置为y中的最右边的n位的值,
x其余各个位保持不变
x:
xxxxXXXXxxxx
111100001111 <= ~(((1<<n)-1) << p)
&------------
xxxxooooxxxx
y:
yyyyyyyyYYYY
000000001111 <=(1<<n)-1
&------------
00000000YYYY << p
xxxxooooxxxx
|------------
xxxxYYYYxxxx
(x&~(((1<<n)-1) << p)) | ((y&(1<<n)-1) <<p)
4.下列表达式中,正确的C赋值表达式是?(C)
A,a=7+b+c=a+7 B,a=7+b++=a+7
C,a=(7+b,b++,a+7) D,a=7+b,c=a+7
5,以下程序语句运行结果为?(D)
int a;
printf("a=%d\n",a);
A,编译出错 B,1024 C,NULL D,不确定值
6,int b=0,x=1;执行语句if(x++)b=x+1;后,x,b的值依次为?(2,3)
7,sizeof(double)的结果是?(8)
8,设f是实型变量,下列表达式中不是逗号表达式的是?(D)
A, f=3.2,1.0 B, f>0,f<10 C, f=2.0,f>0 D, f=(3.2,1.0)
9,PC机中,'\n'在内存占用的字节数是?(1)
10,设c='w',a=1,b=2,d=-5,则表达式'x'+1>c,'y'!=c+2,-a-5*b<d+1,b==a=2的值分别为?
(1,0,1,编译错误)
11,判断变量a,b的值均不为0的逻辑表达式为?
(a!=0&&b!=0)
12,数学式a/(b*c)的c语言表达式是?
( double a/(b*c) )
13,以下程序运行后的输出结果是?(3)
#include
int main()
{
int a;
a=(int)((double)(3/2)+0.5+(int)1.99*2);
printf("%d\n",a);
}
14,在c语言中,如下程序输出的结果为?
char c=250;
unsigned char d;
char f;
d=c+249;
f=c+249;
printf("d=%d\n",d); //243
printf("d=%u\n",d); //243
printf("f=%d\n",f); //-13
printf("f=%u\n",f); //2的32次方-13
( if短的是无符号的数,高位就直接补0 if短的是有符号的数,高位补符号位)