STM32学习及应用笔记二:一次运算符优先级造成的错误

本人在最近一个项目的开发中,出现一个应为疏忽运算符优先级造成的问题,检查了很久才发现问题,所以觉得运算符的优先级问题还是有必要再研究一下。具体的问题是这样的,我采集了传感器的原始数据,然后会对数据进行一些处理,在其中的一种条件下会对一个数进行左移几位并加上一个数。类似的操作在其他地方也有,但只在这个地方忘记了一个括号,所以得出了结果总是存在偏差,只好从头开始查找,花了不少时间才发现这出错误。

其实本人平时还是非常注意代码规范的,但也有一时疏忽的,确实运算符的优先级有时候让人迷惑。下面我们简单的总结一下C语言中运算符的优先级问题。C语言中各运算符的优先级如下表所示:


优先级


运算符


名称或含义


使用形式


结合方向


说明


1


[]


数组下标


数组名[常量表达式]


左到右

 

()


圆括号


(表达式)/函数名(形参表)

 

.


成员选择(对象)


对象.成员名

 

->


成员选择(指针)


对象指针->成员名

 

++


后置自增运算符


++变量名


单目运算符


--


后置自减运算符


--变量名


单目运算符


2


-


负号运算符


-表达式


右到左


单目运算符


(类型)


强制类型转换


(数据类型)表达式

 

++


前置自增运算符


变量名++


单目运算符


--


前置自减运算符


变量名--


单目运算符


*


取值运算符


*指针变量


单目运算符


&


取地址运算符


&变量名


单目运算符


!


逻辑非运算符


!表达式


单目运算符


~


按位取反运算符


~表达式


单目运算符


sizeof


长度运算符


sizeof(表达式)

 

3


/



表达式/表达式


左到右


双目运算符


*



表达式*表达式


双目运算符


%


余数(取模)


整型表达式/整型表达式


双目运算符


4


+



表达式+表达式


左到右


双目运算符


-



表达式-表达式


双目运算符


5


<<


左移


变量<<表达式


左到右


双目运算符


>>


右移


变量>>表达式


双目运算符


6


>


大于


表达式>表达式


左到右


双目运算符


>=


大于等于


表达式>=表达式


双目运算符


<


小于


表达式<表达式


双目运算符


<=


小于等于


表达式<=表达式


双目运算符


7


==


等于


表达式==表达式


左到右


双目运算符


!=


不等于


表达式!= 表达式


双目运算符


8


&


按位与


表达式&表达式


左到右


双目运算符


9


^


按位异或


表达式^表达式


左到右


双目运算符


10


|


按位或


表达式|表达式


左到右


双目运算符


11


&&


逻辑与


表达式&&表达式


左到右


双目运算符


12


||


逻辑或


表达式||表达式


左到右


双目运算符


13


?:


条件运算符


表达式1? 表达式2: 表达式3


右到左


三目运算符


14


=


赋值运算符


变量=表达式


右到左

 

/=


除后赋值


变量/=表达式

 

*=


乘后赋值


变量*=表达式

 

%=


取模后赋值


变量%=表达式

 

+=


加后赋值


变量+=表达式

 

-=


减后赋值


变量-=表达式

 

<<=


左移后赋值


变量<<=表达式

 

>>=


右移后赋值


变量>>=表达式

 

&=


按位与后赋值


变量&=表达式

 

^=


按位异或后赋值


变量^=表达式

 

|=


按位或后赋值


变量|=表达式

 

15


,


逗号运算符


表达式,表达式,…


左到右


从左向右顺序运算

在上表中,同一优先级的运算符,运算次序由结合方向所决定。当然大部分的运算符都是左结合的,与我们的常识一致,但要记住有一部分运算符是右结合的,实在记不住也没有关系,我们可以在编写代码时以( )加以规范。

当然,事情并非我们希望的那么简单。在上表中,如果优先级同为1 的几种运算符同时出现时,想要确定表达式的优先级就会让大家,特别是初学者感到迷惑不解。接下来我们整理了一些容易出错的情况:


优先级问题


表达式


想要的结果


实际结果


.的优先级高于*


*p.f


指针p所指向的对象的某一字段f,即:(*p).f


对p取f偏移作为指针,然后进行解除饮用操作,即:*(p.f)


[]的优先级高于*


int *p[]


P是指向int数组的指针,即:int (*p)[]


P是元素为指向int的指针的数组,即:int *(p[])


函数()优先级高于*


int *p()


p是个函数指针所指函数返回值是int,即:int (*p)()


P是个函数,返回值是int   *,即:int *(p())


==和!=优先级高于位操作


(val&mask!=0)


(val&mask)!=0


val&(mask!=0)


==和!=优先级高于赋值操作


c=getchar()!=EOF


(c=getchar())!=EOF


c=(getchar()!=EOF)


算术运算符高于移位运算符


msb<<4+lsb


(msb<<4)+lsb


msb<<(4+lsb)


逗号运算符的优先级最低


i=1,2


i=(1,2)


(i=1),2

当然,熟记上面这个表中的东西可以减少犯错,但归根到底,最关键是多写代码多使用,熟练了自然就没问题了。

时间: 2024-11-06 11:32:08

STM32学习及应用笔记二:一次运算符优先级造成的错误的相关文章

STM32学习及应用笔记一:SysTick定时器学习及应用

这几年一直使用STM32的MCU,对ARM内核的SysTick计时器也经常使用,但几乎没有仔细了解过.最近正好要在移植一个新的操作系统时接触到了这块,据比较深入的了解了一下. 1.SysTick究竟是什么? 关于SysTick在STM32的资料中并没有详细的介绍,这可能由于SysTick是ARM内核的东西.在<STM32F10xxx参考手册>.<STM32F4xx参考手册>以及<STM32F7xx参考手册>中,介绍时钟的时候仅仅是在使用树上简单的画出了HCLK时钟经过8

学习 Sea.js 笔记(二)

写模块: define(function(require, exports, module) {    使用 require(...) 引入模块.    通过 exports.something = ... 对外提供接口    或通过 module.exports = ... 提供整个接口 ? }); 构建部署: 需要使用 spm 或 Grunt 工具. spm 标准构建工具(已经发布版本3): http://spmjs.io/ 项目标准目录结构:    dist  构建之后的文件夹    sr

swift 笔记 (二十一) —— 高级运算符

高级运算符 位运算符 按位取反: ~ 按位与运算:  & 按位或运算:  | 按位异或运算:  ^ 按位左移运算: << 按位右移动算: >> 溢出运算符 自从swift里面提供了所谓的类型安全之后.我们就不能再用一个 Int.max 进行+1操作了,这样会导致报错.所以swift又提供了一个让我们在知道这会溢出的前提下,继续+1的溢出运算符,这听上去也不错. 溢出加法 &+ 溢出减法 &- 溢出乘法 &* 溢出除法 &/ 溢出取余 &

STM32学习笔记——USART串口(向原子哥和火哥学习)

一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换.USART利用分数波特率发生器提供宽范围的波特率选择. STM32 的串口资源相当丰富的,功能也相当强劲.STM32F103ZET6 最多可提供 5 路串口,有分数波特率发生器,支持同步单向通信和半双工单线通信,支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作.它还允许多处理器通信.

STM32学习笔记(四)——串口控制LED(中断方式)

目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类型并使能串口中断 七.编写中断服务函数函数名格式为函数名格式为 USARTxIRQHandler(x 对应串口号). 八.主函数的实现. 一.时钟使能,包括GPIO的时钟和串口的时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //

STM32学习笔记2——RC522

RC522的学习算下来也有四五天了,今天终于勉强知道大概是怎么一回事了,实现效果如图,大概总结如下: 一.RC522操作流程: 二.M1卡简单介绍: 1.16个扇区,每个扇区分四块 2.每个扇区的块0,1,2为数据块,块3为控制块 3.第0扇区块0为厂家固化,不能更改 三.M1卡的读写: 读和写都是一样的,先定义好读和写的存放数组,读是把块里的数据写入到空数组中,读是把事先赋值的数组的值写入到块中 unsigned char RFID[16];//读 Unsigned charRFID1[16]

STM32学习笔记3(TIM输入捕获)

PWM 输入捕获模式< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" /> 一.概念理解 PWM输入捕获模式时输入捕获模式的特例 1.每个定时器有四个输入通道IC1.IC2.IC3.IC4,且IC1 IC2一组,IC3 IC4一组,并可是设置管脚和寄存器的对应关系 2.两个TI输出映射了两个ICx信号 3.这两个ICx信号分别在相反的极性边沿有效 4.两个边沿

STM32学习笔记2-系统时钟知识及程序配置

一:基本知识 1.  STM32F103ZE有5个时钟源:HSI.HSE.LSI.LSE.PLL. ①.HSI是快速内部时钟,RC振荡器,频率为8MHz,精度不高.   ②.HSE是快速外部时钟,可接石英/陶瓷谐振器,或者接外部时 钟源,频率范围为4MHz~16MHz. ③.LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟. ④.LSE是低速外部时钟,接频率为32.768kHz的石英晶体. ⑤.PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2.HSE或者HSE/2. 倍频

STM32学习笔记1—实习回顾1

一.四步设置GPIO串口 RCC->APB2ENR|=1<<3;    //使能PORTB时钟 GPIOB->CRL&=0XFF0FFFFF;  //位初始化 GPIOB->CRL|=0X00300000;//PB.5  推挽输出 GPIOB->ODR|=1<<5;      //PB.5  输出高 二.三种方法设置io口电平 1.宏定义方式:#define BEEP PBout(8)  BEEP=0; 2.GPIOB->ODR|=1<&