深入理解c语言运算符优先级

深入了解c语言运算符优先级

引言

很多刚学编程的同学对c语言运算符的优先级往往存在一些困惑,对于一些已经入门了的同学一些不太常见的用法也较难理解,比如常见的函数指针:

//函数指针
int (*add)(int a , int b);
//返回指针的函数
int * getAddress(char [] , int n);
//数组指针
int (*a)[]
//指针数组
int * a[];

刚刚接触这些的时候我们往往很难理解这些符号,即使我们理解了也往往对于新的符号也经常出现困惑:

*p++;(*p)++;*++p;++*p;*p.f

而彻底理解C语言运算符的优先级,能让你对这些游刃有余,避免在编程的时候出现困惑,下面我们就一起来探究一下C运算符的优先级吧!

运算符的四要素——符号、操作数、优先级、结合性

符号

符号很容易理解,我们平常所见的+、-、*、/等都是符号,运算符符号指代表某一种运算的符号。划重点:运算符一定是代表了某一种运算,例如:¥虽然也是符号就不是C语言的运算符。

操作数(operand)

操作数是指需要进行运算的数字或者表达式,如1+1,有两个操作数分别是1,和1;再例如 a* b + c / d 这个表达式中+号的两个操作数分别是(a* b)和(c/d)两个表达式的值,操作数不光是数字常量、字符常量也包括可以赋值的各种变量。这些操作数就像是函数的参数,根据“参数”个数的不同运算符分为一元运算符、二元运算符、三元运算符等。

优先级

优先级的概念很好理解,我们小学数学学的先乘除再加减就是一种优先级。给出任意一个表达式例如3+2*y[i]++;因为优先级[] = ++ > * >+ ,我们根据各项运算符优先级不难理解表达式所要表达的含义。

结合性

运算符想要进行运算需要有操作数,结合性顾名思义是操作符与操作数结合的亲密程度。例如前面的例子中++ 和[]拥有相同的优先级但是明显[]与y更加紧密([]距离y更近),所以我们知道是对数组中第i+1个元素进行++,而不是y进行++(这也不和语法)。C语言中运算符的结合性包括从左到右和从右到左两种。从左到右:即优先级相同计算时先算左边的后算右边的;从右到左:即运算符优先级相同先计算左边的在计算右边的。
c语言中运算符的结合性通常都为从左到右,只有前缀一元运算符:* 、&、++(前缀)、–(前缀)、-(负号)、+(正号)、!、~(按位取反)(typename)强制转换、sizeof 、各种赋值运算符、三元运算符:? :这三类为从右到左。

各种运算符的优先级与结合性

下表列出了C语言中运算符的结合性和优先级,可以看出我们小括号()和{}(数组或指针初始化时使用)虽然不算是严格意义上的运算符,但()和{}中的内容通常被认为一个整体(这和数学上的括号意义一致)。所以如果实在确定不了优先级,可以使用() 例如if(a==b&&c==d||d==e&&e==f)等价于if((a==b&&c==d)||(d==e&&e==f)),添加()也使得我们的小程序可读性更高。
除了()和{}之外优先级依次为:一元后缀运算符>一元前缀运算符>算术运算符( * / %)> 算术运算符(± )>位运算符(>>、<<)>关系运算符(>=、>、<、<=)>关系运算符(==、!=)> 位逻辑运算符(依次&、^、|)>逻辑运算符(依次&&、||)>三元运算符(?:)>赋值运算符>逗号运算符(,)。
简单的来说,优先级顺序满足以下几项:

  • 一元后缀运算符>一元前缀运算符>二元运算符>三元运算符
  • 二元运算符中:算术运算符>关系运算符>逻辑运算符>赋值运算符
  • 逻辑运算符: && > ||

结合性比较简单:除了一元前缀运算符、三元运算符和赋值运算符为从右到左以外,其余均为从左到右。

运算符优先级运算符结合性备注
0()(括号)、{}(组合文字)括号和数学运算的括号一致只是声明内部为一个整体,组合文字用了表示数组或结构直接量,严格讲这两个并不算是运算符
1()(函数调用)、++(后缀)、- -(后缀)、[](数组下标). 、->从左到右()和[]在函数和数组声明时也适用此优先级
2++(前缀)、- -(前缀)、*(取值)、&(取指针)、+(正号)、-(符号)、!(取反)、~(按位取反)、sizeof 、 (typename)(强制转换)、从右到左* 在指针声明时也适用此优先级
3* 、/ 、%、从左到右算术运算符
4+、-从左到右算术运算符
5<<、>>从左到右位运算符-移位运算符
6<=、<、>、>=从左到右关系运算符
7==、!=从左到右关系运算符
8&从左到右位逻辑运算符
9^从左到右位逻辑运算符
10|从左到右位逻辑运算符
11&&从左到右逻辑运算符
12||从左到右逻辑运算符
13?:从右到左三元运算符
14=、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=从右到左赋值运算符
15,(逗号运算符)从左到右逗号运算符

补充

关于位运算符

位运算的优先级一直饱受争议,人们认为|、&、^应该与移位运算符(<</>>)一样,例如a&b==c我们往往期待它解析为(a&b)==c,然而事实是它被解析为a&(b==c)。这与我们期望并不相符。主要原因是历史上c并没有&&和||只有&和|,所以位运算&和|被认为是逻辑运算符。

关于条件表达式(?:)

通常优先级和结合性可以解决我们遇到的大部分问题。但有时候运算符本身的含义规定了另一些东西。例如a>b?c,d:e被解释为a>b?(c,d):e,因为(a>b?c),(d:e)这样会毫无意义。同样sizeof (int) *x被解释为(sizeof(int))*x,并非sizeof((int)*x),一般sizeof的操作数最好加上()表示。尽管sizeof n也是合法。
C语言中关于条件表达式的规则为:

logical-OR-expression ? expression : expression

所以对于条件表达式最好按照它的意义去理解,另外条件表达式结合性是从右到左a>b ? a : c>b ? c : b这个表达式被解释为a>b ? a : (c>b ? c : b)

对于一些运算符使用特殊情况的解释

//函数指针
int (*add)(int a , int b);  //括号中*add被看做一个整体,*表明add是一个指针,而int  (.)()表明指针指向的是函数类型。
//返回指针的函数
int * getAddress(char [] , int n);//*getAddress(*) ,*和()两个运算符同时与getAddress结合,而优先级()>*,表明getAddress是一个函数名。
//数组指针
int (*a)[];//括号中*a被看做一个整体,*表明a是一个指针,而int (.)[]表明指针a指向的是数组类型。
//指针数组
int * a[];//*a[],*和[]同时与a结合,而优先级[]>*表明a是一个数组,数组存储的内容为int类型的指针

总结

C语言中运算符优先级是C语法中很重要的一部分,Java、C++、Python、C#中运算符的优先级与C也大多相似。只要理解之后记住这些并不算难,但在实际应用中应当注意在适当的时候使用(),即使你很确定你的表达式没有必要加(),()可以保证我们的代码更加友好、可读。

    原文作者:Sud0x67
    原文地址: https://blog.csdn.net/qq_31383385/article/details/89076948
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞