嵌入式C语言学习笔记—运算符相关知识点总结


概述

学习完《嵌入式C语言》运算符相关的章节后,总感觉自己掌握得不熟练,思考之后得到两个原因:1.自己存在练习不足的情况;2.课程视频其实讲得不够系统。同时也发现了课程讲到的一些亮点。本文既包括自己学习之后,在网上搜罗的知识点,也包括课程中的一些精华。由于详细的课程笔记自己已经在纸质笔记本上记录,本文是作为纸质笔记的补充。
本文涉及的知识点包括在嵌入式C语言的第16、17、18、19、21、22、23、24、25、34、35、38课,生疏时应再次观看。

一、运算符优先级相关的知识点

看了视频课程,也翻阅了一些书籍(自己接触得也不多),发现讲述的运算符都是按类别讲解,算术运算符,关系运算符,逻辑运算符。。。,在每种运算符的章节中都讲述了其优先级,但是没有将优先级放一起讲。而实际写程序或者做题过程中,是会面临各种运算符放一起考虑,谁优先级高,谁优先级低,总是有些混乱。因此做一轮梳理。

  1. C语言运算符的优先级共有15级
  2. 同一优先级的运算符在一起时按结合性决定运算顺序
  3. C语言常用运算符的优先级口诀是:“单算关逻条赋逗”;
  4. 如果加入位运算符,完整口诀是:“单算移关与(按位与),异(按位异或)或(按位或)逻条赋“。
  5. &&的优先级高于||。

C语言运算符优先级表如下:
在这里插入图片描述

二、课程知识点摘记

1.求余运算符(%)限定参与运算的两个操作数为整数。否则编译会报错

dev c++中报错
在这里插入图片描述
kel MDK中报错:
在这里插入图片描述

2.位运算符相关知识点

按位与 &:同1与,结果为原始数据,同0与,结果为0(嵌入式开发中,常用于对位清0)

按位或 |:同1或,结果为1,同0或,结果为原始数据(嵌入式开发中,常用于对位置1)

按位取反 ~:1变0,0变1

按位异或^:同1异或,结果取反,同0异或,结果为原始数据(嵌入式开发中,常用于对指定位取反)

左移 x<<n:表示把x的每一位向左平移n位,右边空位补0;结果= x * 2 n 2 ^n 2n.

右移 x >>n:表示把x的每一位向右平移n位,分有符合数和无符号数两种情况:
① 当x为无符号数时,左边空位补0,称作逻辑移位;
② 当x为有符号数时,左边空位补最高位,称作算术移位;

3.位运算符举例

给定一个变量,其他位不变,只将第6位置1

uint8_t a = 0x55;
//置位操作使用按位或运算符
a = a | 0x40;
//或者 a |= 0x40;也能达到相同的效果;
//更进一步,因为0x40 = 0x01 << 6
a |= 0x01 << 6;  //因为复合复制运算符优先级更低,所以右边不需要加空格。

给定一个变量,其他位不变,只将第2位清零

uint8_t a = 0x55;
//清零使用按位与运算符
a = a & 0xfb;	//0xfb = 1111 1011
//或者 a &= 0xfb;
//更进一步,因为0xfb = ~ (1 << 2)
a &= ~(1 << 2);		//因为按位取反是单目运算符,优先级高于移位运算符,所以表达式中的括号必不可少。

给定一个变量,其他位不变,只将第3位取反
```C
uint8_t a = 0xaa;
//取反使用按位异或运算符,同1异或,结果取反,同0异或,结果不变
a = a ^ 0x08;
//或者a ^= 0x08;效果相同
//进一步追溯0x08的可以表达成
a ^= 0x01 << 3;

3.关系运算符的优先级分布在6级和7级两级

① <, <= , >, >=的优先级为6级,是优先级相对高
② ==, != 的优先级为7级,优先级相对较低

4.逻辑运算符

优先级表格

最高其次最低
逻辑非(!)逻辑与(&&)逻辑或(||)

逻辑运算的“短路”
逻辑运算是自左向右进行结合的,如果左边的表达式已经能决定表达式的结果了,就不会再执行右边的运算
比如:
对于&&:左边表达式为0时,就不再做右边的计算了
对于|| : 左边表达式为1时,也不会再做右边的计算

案例说明:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
	uint8_t a = 10, b = 9;
	if(a != 10 && ++b == 10)
	{
		printf("This is true.\n");
	}
	printf(" b = %d\n", b);
	
	return 0;
} 

程序执行结果如下,说明 ++b == 10的语句并未执行(因为 a != 10的结果为0,已经可以决定整个逻辑表达式的值了,&&右边的表达式被逻辑短路了,所以不执行了)。
在这里插入图片描述

5.关于闰年计算的思考

书上关于闰年计算方法描述为:
如果year能被4整除但不能被100整除,或者year能被400整除的年份被判断为闰年。写成语句就是

int  leap = (year % 4 == 0 && year % 100 != 0)|| (year % 400 == 0);

在编写具体代码时产生一个疑问,这条语句和下面一条语句究竟是否等效的呢?

int leap =  year % 4 == 0 && year % 100 != 0 || year % 400 == 0;

首先进行分析,因为算术运算符优先级> 关系运算符 > && >|| > 赋值运算符
所以根据语句执行分析,判断是等效的。

但如何通过编程证明这一点呢?
因为算术运算符和关系运算符高于逻辑运算符,所以判断的重点在与 year % 100 != 0究竟和谁结合?
要能设计出一种条件,使得year % 100 != 0 向前结合 和向后结合的两种情况,表达式的值不一样。

我们假设year % 4 == 0 为假,那么此时会发生逻辑短路,如果 是向前结合,那么只会短路year % 100 != 0,如果是向后结合,那么会短路 year % 100 != 0 || year % 400 == 0。

代码如下:

int main(void)
{
	int year = 2005;
	int a =1, b = 0, c = 1;
	
	//int leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
	int leap = (a = year % 4 == 0) && (b = year % 100 != 0) || (c = year % 400 == 0);
	printf(" a = %d, b = %d, c = %d\n", a, b, c);
	
	return 0;	
}

执行结果如下,说明b被短路,c未被短路,说明 b = year % 100 != 0 是向左结合的。
![在这里插入图片描述](https://img-blog.csdnimg.cn/0eae12ba556a4f158fc5d88328e8fa20.png

但为什么C语言书籍上都是第一种写法呢?
我的理解,我们写程序要写“笨的”但是“便于理解”的程序,而不是写“聪明”但是读起来很费劲的程序。

三、课程中提到的编程规范摘要

① 对于二元运算符,建议运算符前后加空格
比如:

int a = 10;

再比如:

if(a > b)
{
}

② 为避免出现将== 写成=,如果关系运算符右侧为常量值,建议将常量放在左侧,变量放在右侧,这样,如果出现将==写成=的情况,编译会报错。
即将

if(a == 9)
{
}

写成

if(9 == a)
{
}

③ 在编写包括&&的表达式时,将最可能为假的子表达式写在最左边;在编写包括||的表达式时,将最可能为真的表达式写在左边,可以提高程序执行效率;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值