本人在最近一个项目的开发中,出现一个应为疏忽运算符优先级造成的问题,检查了很久才发现问题,所以觉得运算符的优先级问题还是有必要再研究一下。具体的问题是这样的,我采集了传感器的原始数据,然后会对数据进行一些处理,在其中的一种条件下会对一个数进行左移几位并加上一个数。类似的操作在其他地方也有,但只在这个地方忘记了一个括号,所以得出了结果总是存在偏差,只好从头开始查找,花了不少时间才发现这出错误。 其实本人平时还是非常注意代码规范的,但也有一时疏忽的,确实运算符的优先级有时候让人迷惑。下面我们简单的总结一下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是指向int数组的指针,即:int (*p)[] | P是元素为指向int的指针的数组,即:int *(p[]) | | | p是个函数指针所指函数返回值是int,即:int (*p)() | P是个函数,返回值是int *,即:int *(p()) | | | | | | | | | | | | | | | | | 当然,熟记上面这个表中的东西可以减少犯错,但归根到底,最关键是多写代码多使用,熟练了自然就没问题了。
|