C語言運算子優先順序和結合性一覽表

2020-07-16 10:04:24
所謂優先順序就是當一個表示式中有多個運算子時,先計算誰,後計算誰。這個其實我們在小學學算術的時候就學過,如1+4÷2

但是C語言中的運算子已經遠不止四則運算中的加減乘除了,還有其他很多運算子。當它們出現在同一個表示式中時先計算誰後計算誰呢?所以本節還是有必要講一下的。最後我還會將所有運算子展示出來,然後告訴你哪個優先順序高、哪個優先順序低。

首先不需要專門記憶,也沒有必要。因為作為初學者,哪個優先順序高、哪個優先順序低我們很難記住。就算死記硬背記住了,時間長不用也會忘記。所以當一個表示式中有多個運算子時,如果不知道哪個優先順序高哪個優先順序低就查一下優先順序表,附錄E有一個運算子優先順序表。此外用的時間長了自然而然就記住了,這樣記才會記得深刻。

而且事實上在程式設計的時候也不需要考慮優先順序的問題。因為如果不知道優先順序高低的話,加一個括號就可以了,因為括號( )的優先順序是最高的。比如前面的程式中:

k = (j>i) && (8==i);

根據運算子的優先順序,這條語句完全可以寫成:

k = j>i && 8==i;

但是第一種寫法別人一看就知道先計算誰後計算誰。

而且加圓括號也是一種程式設計規範,因為程式不只是寫給自己看。

此外運算子還有“目”和“結合性”的概念,這個很簡單。“目”就是“眼睛”的意思,一個運算子需要幾個數就叫“幾目”。比如加法運算子+,要使用這個運算子需要兩個數,如 3+2。對+而言,3 和 2 就像它的兩隻眼睛,所以這個運算子是雙目的。

C語言中大多數的運算子都是雙目的,也有單目和三目的。單目運算子比如邏輯非,如!1,它就只有一隻眼睛,所以是單目的。整個C語言中只有一個三目運算子,即條件運算子? :。這個稍後講到條件語句的時候再介紹。關於“目”大家了解一下就行了。

那麼“結合性”是什麼呢?上面講的優先順序都是關於優先順序不同的運算子參與運算時先計算誰後計算誰。但是如果運算子的優先順序相同,那麼先計算誰後計算誰呢?這個就是由“結合性”決定的。

比如1+2×3÷4,乘和除的優先順序相同,但是計算的時候是從左往右,即先計算乘再計算除,所以乘和除的結合性就是從左往右。就是這麼簡單!

C語言中大多數運算子的結合性都是從左往右,只有三個運算子是從右往左的。一個是單目運算子,另一個是三目運算子,還有一個就是雙目運算子中的賦值運算子=。雙目運算子中只有賦值運算子的結合性是從右往左的,其他的都是從左往右。運算子的“結合性”也不要死記,在不斷使用中就記住了。

運算子優先順序和結合性一覽表

優先順序

運算子

名稱或含義

使用形式

結合方向

說明

1

[]

陣列下標

陣列名[常數表示式]

左到右

 

()

圓括號

(表示式)
函數名(形參表)

 

.

成員選擇(物件)

物件.成員名

 

->

成員選擇(指標)

物件指標->成員名

 

2

-

負號運算子

-表示式

右到左

單目運算子

(型別)

強制型別轉換

(資料型別)表示式

 

++

自增運算子

++變數名
變數名++

單目運算子

--

自減運算子

--變數名
變數名--

單目運算子

*

取值運算子

*指標變數

單目運算子

&

取地址運算子

&變數名

單目運算子

!

邏輯非運算子

!表示式

單目運算子

~

按位元取反運算子

~表示式

單目運算子

sizeof

長度運算子

sizeof(表示式)

 

3

/

表示式 / 表示式

左到右

雙目運算子

*

表示式*表示式

雙目運算子

%

餘數(取模)

整型表示式%整型表示式

雙目運算子

4

+

表示式+表示式

左到右

雙目運算子

-

表示式-表示式

雙目運算子

5

<<

左移

變數<<表示式

左到右

雙目運算子

>>

右移

變數>>表示式

雙目運算子

6

>

大於

表示式>表示式

左到右

雙目運算子

>=

大於等於

表示式>=表示式

雙目運算子

<

小於

表示式<表示式

雙目運算子

<=

小於等於

表示式<=表示式

雙目運算子

7

==

等於

表示式==表示式

左到右

雙目運算子

!=

不等於

表示式!= 表示式

雙目運算子

8

&

按位元與

表示式&表示式

左到右

雙目運算子

9

^

按位元互斥或

表示式^表示式

左到右

雙目運算子

10

|

按位元或

表示式|表示式

左到右

雙目運算子

11

&&

邏輯與

表示式&&表示式

左到右

雙目運算子

12

||

邏輯或

表示式||表示式

左到右

雙目運算子

13

?:

條件運算子

表示式1? 表示式2: 表示式3

右到左

三目運算子

14

=

賦值運算子

變數=表示式

右到左

 

/=

除後賦值

變數/=表示式

 

*=

乘後賦值

變數*=表示式

 

%=

取模後賦值

變數%=表示式

 

+=

加後賦值

變數+=表示式

 

-=

減後賦值

變數-=表示式

 

<<=

左移後賦值

變數<<=表示式

 

>>=

右移後賦值

變數>>=表示式

 

&=

按位元與後賦值

變數&=表示式

 

^=

按位元互斥或後賦值

變數^=表示式

 

|=

按位元或後賦值

變數|=表示式

 

15

,

逗號運算子

表示式,表示式,…

左到右

 


上表中可以總結出如下規律:
  1. 結合方向只有三個是從右往左,其餘都是從左往右。
  2. 所有雙目運算子中只有賦值運算子的結合方向是從右往左。
  3. 另外兩個從右往左結合的運算子也很好記,因為它們很特殊:一個是單目運算子,一個是三目運算子。
  4. C語言中有且只有一個三目運算子。
  5. 逗號運算子的優先順序最低,要記住。
  6. 此外要記住,對於優先順序:算術運算子 > 關係運算子 > 邏輯運算子 > 賦值運算子。邏輯運算子中“邏輯非 !”除外。

一些容易出錯的優先順序問題

上表中,優先順序同為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

這些容易出錯的情況,希望讀者好好在編譯器上偵錯偵錯,這樣印象會深一些。一定要多偵錯,光靠看程式碼,水平是很難提上來的。偵錯程式碼才是最長水平的。