運算過程存在優先級和結合性兩個問題。在數學的四則運算中規定,先算括號,再算乘除,最後算加減,不同運算符具有不同的計算順序,這就是運算優先級問題;同時,還規定同級運算從左往右依次計算,這是計算的結合性問題。在C/C++中,運算符也需要注意優先級和結合性,而且C/C++中的運算符很多,遠比數學四則運算複雜,它們的優先級和結合性如下表所示:
優先級
運算符
名稱或含義
使用形式
結合方向
說明
1
[]
數組下標
數組名[常量表達式]
左到右
()
圓括號
(表達式)
函數名(形參表)
.
成員選擇(對象)
對象.成員名
->
成員選擇(指針)
對象指針->成員名
2
-
負號運算符
-表達式
右到左
單目運算符
(類型)
強制類型轉換
(數據類型)表達式
++
自增運算符
++變量名 變量名++
單目運算符
--
自減運算符
--變量名 變量名--
單目運算符
*
取值運算符
*指針變量
單目運算符
&
取地址運算符
&變量名
單目運算符
!
邏輯非運算符
!表達式
單目運算符
~
按位取反運算符
~表達式
單目運算符
sizeof
長度運算符
sizeof(表達式)
3
/
除
表達式 / 表達式
左到右
雙目運算符
*
乘
表達式*表達式
雙目運算符
%
餘數(取模)
整型表達式%整型表達式
雙目運算符
4
+
加
表達式+表達式
左到右
雙目運算符
-
減
表達式-表達式
雙目運算符
5
<<
左移
變量<<表達式
左到右
雙目運算符
>>
右移
變量>>表達式
雙目運算符
6
>
大於
表達式>表達式
左到右
雙目運算符
>=
大於等於
表達式>=表達式
雙目運算符
<
小於
表達式<表達式
雙目運算符
<=
小於等於
表達式<=表達式
雙目運算符
7
==
等於
表達式==表達式
左到右
雙目運算符
!=
不等於
表達式!= 表達式
雙目運算符
8
&
按位與
表達式&表達式
左到右
雙目運算符
9
^
按位異或
表達式^表達式
左到右
雙目運算符
10
|
按位或
表達式|表達式
左到右
雙目運算符
11
&&
邏輯與
表達式&&表達式
左到右
雙目運算符
12
||
邏輯或
表達式||表達式
左到右
雙目運算符
13
?:
條件運算符
表達式1? 表達式2: 表達式3
右到左
三目運算符
14
=
賦值運算符
變量=表達式
右到左
/=
除後賦值
變量/=表達式
*=
乘後賦值
變量*=表達式
%=
取模後賦值
變量%=表達式
+=
加後賦值
變量+=表達式
-=
減後賦值
變量-=表達式
<<=
左移後賦值
變量<<=表達式
>>=
右移後賦值
變量>>=表達式
&=
按位與後賦值
變量&=表達式
^=
按位異或後賦值
變量^=表達式
|=
按位或後賦值
變量|=表達式
15
,
逗號運算符
表達式,表達式,…
左到右
總結上表規律:
(1)結合性
所有雙目運算符中只有賦值運算符的結合方向是從右往左。另外兩個從右往左結合的運算符也很好記,因為它們很特殊:一個是單目運算符,一個是三目運算符。其餘都是從左往右的結合性。
(2)優先級
基本優先級:算術運算符 > 關係運算符 > 邏輯運算符 > 賦值運算符。比較特殊的是邏輯非(!)作為單目運算符,優先級高於所有的雙目和三目運算符。複合運算符的級別比其他運算符都低,僅僅高於逗號運算符。
優先級的細節問題:乘除模運算高於加減。二進位移位運算 > 關係運算符 > 位運算符。如果添加了括號,那麼括號的優先級最高。
(3)目運算
一個運算符需要n個操作數就稱為n目運算符。例如,++、--只需要一個操作數,就是單目運算符;+、-、*、/的兩邊都有操作數,稱為雙目運算符;?:是三目運算符,也是C語言中唯一的三目運算符。
當一個表達式中出現多個運算符時,C/C++會先比較各個運算符的優先級,按照優先級從高到低的順序依次執行;當遇到優先級相同的運算符時,再根據結合性決定先執行哪個運算符:如果是左結合性就先執行左邊的運算符,如果是右結合性就先執行右邊的運算符。
分析一:表達式a+b*c。
根據優先級,*大於+,那麼應該先計算乘法,再計算加法。所以C/C++和數學中的規則一樣。
分析二:表達式a/b*c。
*和/的優先級相同,那麼看結合性,*和/都是從左向右結合,因此先算除法,再算乘法。所以C語言和數學中的規則一樣。類似於這種從左向右結合方式,稱為左結合性;那麼先執行右邊的稱為右結合性。
分析三:表達式d=a+b--
由於--運算優先級高於+,--是右到左的結合性。右邊沒有變量,這時直接執行a+b,把值賦給d。然後--才開始執行b-1的操作。
分析四:表達式d=a+--b
由於--運算優先級高於+,--是右到左的結合性,於是執行--b得到b-1;然後執行才進行加法運算,所以d的值是a+b-1。
在指針和函數中關於*、&、()的優先級要特別注意:
優先級問題
表達式
經常誤認為的結果
實際結果
.的優先級高於*(->操作符用於消除這個問題)
*p.f
p所指對象的欄位f,等價於:
(*p).f
對p取f偏移,作為指針,然後進行解除引用操作,等價於:
*(p.f)
[]高於*
int*ap[]
ap是個指向int數組的指針,等價於:
int(*ap)[]
ap是個元素為int指針的數組,等價於:
int*(ap[])
函數()高於*
int*fp()
fp是個函數指針,所指函數返回int,等價於:
int(*fp)()
fp是個函數,返回int*,等價於:
int*(fp())
此外,位運算、關係運算與算術運算符之間,也是分析優先級容易錯誤的地方:
優先級問題
表達式
經常誤認為的結果
實際結果
==和!=高於位操作
(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
最後,逗號運算符在所有運算符中優先級最低:
等價於
溫馨提示:為了防止出現優先級錯誤,在實際編程中,記得優先計算的運算添加括號。