優先級
|
運算符
|
名稱或含義
|
使用形式
|
結合方向
|
說明
|
1
|
[]
|
數組下標
|
數組名[常量表達式]
|
左到右
|
|
()
|
圓括號
|
(表達式)/函數名(形參表)
|
|||
.
|
成員選擇(對象)
|
對象.成員名
|
|||
->
|
成員選擇(指針)
|
對象指針->成員名
|
|||
2
|
-
|
負號運算符
|
-表達式
|
右到左
|
單目運算符
|
(類型)
|
強制類型轉換
|
(數據類型)表達式
|
|||
++
|
自增運算符
|
++變量名/變量名++
|
單目運算符
|
||
--
|
自減運算符
|
--變量名/變量名--
|
單目運算符
|
||
*
|
取值運算符
|
*指針變量
|
單目運算符
|
||
&
|
取地址運算符
|
&變量名
|
單目運算符
|
||
!
|
邏輯非運算符
|
!表達式
|
單目運算符
|
||
~
|
按位取反運算符
|
~表達式
|
單目運算符
|
||
sizeof
|
長度運算符
|
sizeof(表達式)
|
|||
3
|
/
|
除
|
表達式/表達式
|
左到右
|
雙目運算符
|
*
|
乘
|
表達式*表達式
|
雙目運算符
|
||
%
|
余數(取模)
|
整型表達式/整型表達式
|
雙目運算符
|
||
4
|
+
|
加
|
表達式+表達式
|
左到右
|
雙目運算符
|
-
|
減
|
表達式-表達式
|
雙目運算符
|
||
5
|
<<
|
左移
|
變量<<表達式
|
左到右
|
雙目運算符
|
>>
|
右移
|
變量>>表達式
|
雙目運算符
|
||
6
|
>
|
大於
|
表達式>表達式
|
左到右
|
雙目運算符
|
>=
|
大於等於
|
表達式>=表達式
|
雙目運算符
|
||
<
|
小於
|
表達式<表達式
|
雙目運算符
|
||
<=
|
小於等於
|
表達式<=表達式
|
雙目運算符
|
||
7
|
==
|
等於
|
表達式==表達式
|
左到右
|
雙目運算符
|
!=
|
不等於
|
表達式!= 表達式
|
雙目運算符
|
||
8
|
&
|
按位與
|
表達式&表達式
|
左到右
|
雙目運算符
|
9
|
^
|
按位異或
|
表達式^表達式
|
左到右
|
雙目運算符
|
10
|
|
|
按位或
|
表達式|表達式
|
左到右
|
雙目運算符
|
11
|
&&
|
邏輯與
|
表達式&&表達式
|
左到右
|
雙目運算符
|
12
|
||
|
邏輯或
|
表達式||表達式
|
左到右
|
雙目運算符
|
13
|
?:
|
條件運算符
|
表達式1? 表達式2: 表達式3
|
右到左
|
三目運算符
|
14
|
=
|
賦值運算符
|
變量=表達式
|
右到左
|
|
/=
|
除后賦值
|
變量/=表達式
|
|||
*=
|
乘后賦值
|
變量*=表達式
|
|||
%=
|
取模后賦值
|
變量%=表達式
|
|||
+=
|
加后賦值
|
變量+=表達式
|
|||
-=
|
減后賦值
|
變量-=表達式
|
|||
<<=
|
左移后賦值
|
變量<<=表達式
|
|||
>>=
|
右移后賦值
|
變量>>=表達式
|
|||
&=
|
按位與后賦值
|
變量&=表達式
|
|||
^=
|
按位異或后賦值
|
變量^=表達式
|
|||
|=
|
按位或后賦值
|
變量|=表達式
|
|||
15
|
,
|
逗號運算符
|
表達式,表達式,…
|
左到右
|
從左向右順序運算
|
C語言中,運算符的運算優先級共分為15級。1級最高,15級最低。在表達式中,優先級較高的先於優先級較低的進行運算。 而在一個運算量兩側的運算符優先級相同時, 則按運算符的結合性所規定的結合方向處理。 C語言中各運算符的結合性分為兩種,即左結合性(自左至右)和右結合性(自右至左)。例如算術運算符的結合性是自左至右,即先左后右。如有表達式x-y+z則y應先與“-”號結合, 執行x-y運算,然后再執行+z的運算。這種自左至右的結合方向就稱為“左結合性”。而自右至左的結合方向稱為“右結合性”。 最典型的右結合性運算符是賦值運算符。如x=y=z,由於“=”的右結合性,應先執行y=z再執行x=(y=z)運算。 C語言運算符中有不少為右結合性,應注意區別,以避免理解錯誤。
在標准C語言的文檔里,對操作符的結合性並沒有作出非常清楚的解釋。一個滿分的回答是:它是仲裁者,在幾個操作符具有相同的優先級時決定先執行哪一個。
每個操作符擁有某一級別的優先級,同時也擁有左結合性或右結合性。優先級決定一個不含括號的表達式中操作數之間的“緊密”程度。例如,在表達式a*b+c中,乘法運算的優先級高於加法運算符的優先級,所以先執行乘法a*b,而不是加法b+c。
但是,許多操作符的優先級都是相同的。這時,操作符的結合性就開始發揮作用了。在表達式中如果有幾個優先級相同的操作符,結合性就起仲裁的作用,由它決定哪個操作符先執行。像下面這個表達式:
int a, b=1, c=2;
a=b=c;
我們發現,這個表達式只有賦值符,這樣優先級就無法幫助我們決定哪個操作先執行,是先執行b=c
呢,還是先執行a=b?如果按前者,a的結果為2,如果按后者,a的結果為1。
所有的賦值符(包括復合賦值)都具有右結合性,就是說在表達式中最右邊的操作最先執行,然后從右到左依次執行。這樣,先賦值給b,然后b再賦值給a,最終a的值是2。類似地,具有左結合性的操作符(如位操作符“&”和“|”)則是從左至右依次執行。所以,遇到一個表達式時,先根據運算符的優先級將表達式拆分成幾個子表達式,然后在每個子表達式中根據運算符的結合性來進一步確定執行的順序。
【特殊情況】
看下面這個C表達式:
a+++b;
結果是(a++)+b還是a+(++b)呢?答案是前者,因為在遇到這種情況時,C編譯器會將表達式按照從左往右的順序盡量匹配出一個子表達式,所以當C編譯器遇到a且后面有3個+號時,會首先嘗試匹配a+++,當然這是沒有意義的,所以接着嘗試a++發現這是有意義的匹配,因此確定a++為第一個子表達式,然后再接着匹配+號和b。因此結果是(a++)+b。
這種情況不能算是上面所討論的運算符優先級和結合性的特例,因為它發生在優先級和結合性判斷之前,但確實具有一些迷惑性,所以建議在遇到這種情況時給其加上括號,以增加可讀性且避免可能發生的不必要的錯誤。
(自增自減運算符存在於C/C++/C#/Java等高級語言中,它的作用是在運算結束前(前置自增自減運算符)或后(后置自增自減運算符)將變量的值加(或減)一。
int j=4;
i++;
++j;
printf("%d, %d\n", i, j);
int j=4;
int a = i++;
int b = ++j;
printf("%d, %d\n", a, b);
結果又是多少呢?這里就開始體現出++前置與后置的區別了,結果是3,5。結合此例,我們回頭再來理解一下“++前置:i自增1后再參與其它運算;++后置:i參與運算后,i的值再自增1”。很明顯,a = i++;由於是先執行賦值運算,再自增,所以結果是a=3,i=4;而b = ++j;則因先自增,然后再賦值,所以b,j均為5。
int a=1,b=5;
int c=a+++b;
printf("a:%d,b:%d,c:%d",a,b,c);
用例3:
int a=1,b=5;
int c=(a++)+(b++);// int c=a+++b++
printf("a:%d,b:%d,c:%d",a,b,c);
用例4:
int a=1,b=5;
int c=(a++)+(++b);
printf("a:%d,b:%d,c:%d",a,b,c);