C语言学习及应用笔记之一:C运算符优先级及使用问题
C语言中的运算符绝对是C语言学习和使用的一个难点,因为在2011版的标准中,C语言的运算符的数量超过40个,甚至比关键字的数量还要多。这些运算符有单目运算符、双目运算符以及三目运算符,又涉及到左结合和右结合的问题,真是令人眼花缭乱。
1、运算符及优先级
运算符多可能使用更灵活方便,但这还涉及到运算符之间的优先级问题。我们做四则运算式时,有先乘除后加减的规定,在C语言的这些运算符中自然也是有的,但40多个运算符排起优先级来,使用就不那么容易了。
接下来我们简单的总结一下C语言中运算符以及他们的优先级。C语言中各运算符的优先级如下表所示:
优先级 |
运算符 |
名称或含义 |
使用形式 |
结合方向 |
说明 |
1 |
[] |
数组下标 |
数组名[常量表达式] |
左到右 |
|
() |
圆括号 |
(表达式)/函数名(形参表) |
|||
. |
成员选择(对象) |
对象.成员名 |
|||
-> |
成员选择(指针) |
对象指针->成员名 |
|||
++ |
后置自增运算符 |
++变量名 |
单目运算符 |
||
-- |
后置自减运算符 |
--变量名 |
单目运算符 |
||
2 |
- |
负号运算符 |
-表达式 |
右到左 |
单目运算符 |
(类型) |
强制类型转换 |
(数据类型)表达式 |
|||
++ |
前置自增运算符 |
变量名++ |
单目运算符 |
||
-- |
前置自减运算符 |
变量名-- |
单目运算符 |
||
* |
取值运算符 |
*指针变量 |
单目运算符 |
||
& |
取地址运算符 |
&变量名 |
单目运算符 |
||
! |
逻辑非运算符 |
!表达式 |
单目运算符 |
||
~ |
按位取反运算符 |
~表达式 |
单目运算符 |
||
sizeof |
长度运算符 |
sizeof(表达式) |
|||
3 |
/ |
除 |
表达式/表达式 |
左到右 |
双目运算符 |
* |
乘 |
表达式*表达式 |
双目运算符 |
||
% |
余数(取模) |
整型表达式/整型表达式 |
双目运算符 |
||
4 |
+ |
加 |
表达式+表达式 |
左到右 |
双目运算符 |
- |
减 |
表达式-表达式 |
双目运算符 |
||
5 |
<< |
左移 |
变量<<表达式 |
左到右 |
双目运算符 |
>> |
右移 |
变量>>表达式 |
双目运算符 |
||
6 |
> |
大于 |
表达式>表达式 |
左到右 |
双目运算符 |
>= |
大于等于 |
表达式>=表达式 |
双目运算符 |
||
< |
小于 |
表达式<表达式 |
双目运算符 |
||
<= |
小于等于 |
表达式<=表达式 |
双目运算符 |
||
7 |
== |
等于 |
表达式==表达式 |
左到右 |
双目运算符 |
!= |
不等于 |
表达式!= 表达式 |
双目运算符 |
||
8 |
& |
按位与 |
表达式&表达式 |
左到右 |
双目运算符 |
9 |
^ |
按位异或 |
表达式^表达式 |
左到右 |
双目运算符 |
10 |
| |
按位或 |
表达式|表达式 |
左到右 |
双目运算符 |
11 |
&& |
逻辑与 |
表达式&&表达式 |
左到右 |
双目运算符 |
12 |
|| |
逻辑或 |
表达式||表达式 |
左到右 |
双目运算符 |
13 |
?: |
条件运算符 |
表达式1? 表达式2: 表达式3 |
右到左 |
三目运算符 |
14 |
= |
赋值运算符 |
变量=表达式 |
右到左 |
|
/= |
除后赋值 |
变量/=表达式 |
|||
*= |
乘后赋值 |
变量*=表达式 |
|||
%= |
取模后赋值 |
变量%=表达式 |
|||
+= |
加后赋值 |
变量+=表达式 |
|||
-= |
减后赋值 |
变量-=表达式 |
|||
<<= |
左移后赋值 |
变量<<=表达式 |
|||
>>= |
右移后赋值 |
变量>>=表达式 |
|||
&= |
按位与后赋值 |
变量&=表达式 |
|||
^= |
按位异或后赋值 |
变量^=表达式 |
|||
|= |
按位或后赋值 |
变量|=表达式 |
|||
15 |
, |
逗号运算符 |
表达式,表达式,… |
左到右 |
从左向右顺序运算 |
在上表中,我们归纳了运算符、个运算符的功能、通常的应用表达式形式以及结合性。说到结合性主要应用于相同优先级的运算符,运算次序由结合方向所决定。绝大部分的运算符都是左结合的,与我们的常识一致。不过有一部分运算符是右结合的,这些就需要记忆了,但记忆有时候却不见得百分百准确,所以我们可以在编写代码时以( )加以规范。
2、优先级的一些特别说明
我们见面归纳了运算符的用法,但这只是一般性情况,实际的使用情况有时候依然让人迷惑。比方说,在上表中,如果优先级同为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 |
那么是不是有了上面的总结就完事大吉了呢?当然不可能,且不说我们的总结很不完备,就算你记住了所有的规则,在使用过程中仍然有可能漏洞百出,最好的办法是养成良好的编码习惯。
3、由优先级引发的错误
优先级问题经常会造成一些意想不到的结果,有的甚至是非常严重的。本人在编写程序时,就出现过一些因为疏忽运算符优先级造成的问题,而且检查起来非常不容易发现。
例如,有一次,我们采集了传感器的原始数据,然后会对数据进行一些处理,在其中的一种条件下会对一个数进行左移几位并加上一个数。由于算术运算符的优先级大于移位运算符,而程序员忘记了给移位操作加括号,所以得出了结果总是有误,只好从头开始查找,花了不少时间才发现这出错误。如msb<<4+lsb和(msb<<4)+lsb是完全不一样,因为算术运算符的优先级大于移位运算符。
还有一次,我们定义一个指向函数的指针数组用于回调函数的操作。定义时,没有考虑到指针运算符、函数运算符以及数组运算符的优先级问题而造成调用出错。如,void (*p[])f()的形式,如果写成void *p[]f()的形式就完全错误了。
当然,如果能够熟记各种运算符的优先级也许能解决上面的问题,但这实际上却很难达到,因为应用是非常灵活的,你不可能时时刻刻只关注于此。我觉得养成良好的编码习惯以及多多练习似乎更有效。
欢迎关注:
C语言学习及应用笔记之一:C运算符优先级及使用问题相关推荐
- C语言学习及复习笔记-【5】C 运算符
文章目录 5. C 运算符 5.1 关系运算符 5.2 逻辑运算符 5.3 位运算符 5.4 杂项运算符 ↦ sizeof & 三元 5.5 例子 1). 利用异或 ^ 来交换两个数的值,而且 ...
- 重读The C programming Lanuage 笔记二:运算符优先级
运算符的优先级和结合性有明确的规定,但是,除少数例外情况外,表达式的求值次序没有定义,甚至某些有副作用的子表达式也没有定义. 也就是说运算符的定义保证了其操作数按某一特定的顺序求值,否则具体实现可以自 ...
- c语言变量的值也可以不改变6,C语言学习复盘整理笔记(六)
第六周:程序设计与C语言 6.1数组 数据可以存放在变量里,每一个变量有一个名字,有一个类型,还有它的生存空间.如果我们需要保存一些相同类型.相似含义.相同生存空间的数据,我们可以用数组来保存这些数据 ...
- C语言学习(个人笔记)
C语言 01-计算机基本概念 什么是计算机 计算机特点 计算机是一种电器,有两种状态,**通电,断电 ** 用0和1表示这两种状态 计算机能识别的所有指令也是由0和1组成的 计算机的储存和操作数据也是 ...
- C语言学习及应用笔记之三:C语言const关键字及其使用
在C语言程序中,const关键字也是经常会用到的一个关键字,那么使用const关键字的目的是什么呢?事实上,在程序中使用const关键字的主要目的就是为了向使用者传递设计者的一些意图. 事实上,无论我 ...
- C语言学习及应用笔记之七:C语言中的回调函数及使用方式
我们在使用C语言实现相对复杂的软件开发时,经常会碰到使用回调函数的问题.但是回调函数的理解和使用却不是一件简单的事,在本篇我们根据我们个人的理解和应用经验对回调函数做简要的分析. 1.什么是回调函数 ...
- C语言学习及应用笔记之五:C语言typedef关键字及其使用
在C语言中有一个typedef关键字,其用来定义用户自定义类型.当然,并不是真的创造了一种数据类型,而是给已有的或者符合型的以及复杂的数据类型取一个我们自己更容易理解的别名.总之,可以使用typede ...
- C语言学习及应用笔记之二:C语言static关键字及其使用
C语言有很多关键字,大多关键字使用起来是很明确的,但有一些关键字却要相对复杂一些.我们这里要说明的static关键字就是如此,它的功能很强大,相应的使用也就更复杂. 一般来说static关键字的常见用 ...
- C语言学习及应用笔记之六:C语言extern关键字及其使用
在C语言中,修饰符extern用在变量或者函数的声明前,用来以标识变量或者函数的定义在别的文件中,提示编译器遇到此变量或者函数时,在其它文件中寻找其定义.extern关键字的用法有几种,我们下面对其进 ...
最新文章
- python 判断图片是否损坏_检查图片是否损坏、图片后缀是否与实际图片类型对应 - Python...
- [导入]为Exchange Server安装WAP电子邮件网关
- python安装报错ox000007b_Python沙箱逃逸的n种姿势
- 大神如何一招完美解决Hadoop集群无法正常关闭的问题!| 博文精选
- linux中内存管理方法的总结,Linux内存管理-free学习心得
- 解决listview addheader EditText焦点问题
- study - 收藏集 - 掘金
- Linux-apache的编译安装1
- python魅力_Python逐渐失去魅力
- 统计模型混响信号预报matlab,基于MATLAB的混响效果设计课程设计
- java adt eclipse_Eclipse安装ADT插件
- Linux常用软件包(常用命令)
- aspeed显卡安装ubuntu驱动
- 在sagemath中运行python文件
- win10重装系统,屏幕亮度调节失效修复
- 设计方面的优秀网站推荐QWQ
- 2020计算机二级office知识点,2020年计算机二级Word常考点汇总
- 内部软件技术文档怎么做?
- CSS overflow用法
- 拼多多:item_search-根据关键词取商品列表接口,拼多多关键词搜索API接口,拼多多上货API接口,拼多多API接口