細說c語言的優先級

0. 爲什麼要掌握優先級
1. 優先級
1.1 優先級圖表
1.2 運算符實例
1.3 優先級順口溜
2. 結合性
3. 參考資料

    寫代碼的時候,常會翻看的一個表就是“c語言運算符優先級表”。c的運算符優先級常常很讓人頭疼。其實,在大學裏學習c的時候,老師告訴大家這個不用一定背下來,用的時候可以找書,或者加小括號就可以了。我聽了,但是後來發現錯了。很多人都聽了,但不是每個人都發現這是錯的。以至於有人覺得把優先級背下來是“沒事閒的”(http://zhidao.baidu.com/question/155120432.html?an=0&si=1)。

0. 爲什麼要掌握優先級

    想想這兩個問題:
        a. 讀別人的代碼,遇到優先級問題看不懂,怎麼辦?
        b. 一堆的括號,美觀嗎?
        本想貼一張畫來裝飾牆壁,卻用了一堆紙來固定!
        有人說代碼寫多了,自然就會了。這個是很寬泛的說法。看你寫的代碼的水準,有些東西可能你一直都接觸不到,何談熟練。有些東西一定要梳理,總結。

1. 優先級

1.1 優先級圖表


  •     優先級最高者不是真正意義上的運算符,包括:數組下標,函數調用,結構體成員選擇符。
  •     單目運算符的優先級次之。(! ~ ++ -- - (type) * & sizeof)
  •     然後是雙目運算符。雙目運算符裏, 算數運算符(* / % + -)優先級最高, 移位(<< >>)次之, 關係運算符(< <= > >= != ==)再次之, 接着是位運算符(& ^ | ),邏輯運算符(&& ||) 條件運算符(?: 三目),賦值運算符(= ...)。
  •     任何一個邏輯運算符的優先級低於任何一個關係運算符。
  •     移位運算符的優先級比算數運算符要低,但是比關係運算符要高。

1.2 運算符實例
    a. while (c = getc(in) != EOF)
        putc(c, out)
        循環的意思是複製一個文件到另一個文件。但是由於!=的優先級比賦值運算符的優先級高,所以c被賦予了getc()的返回值與EOF比較後的布爾值,結果向out中寫入了一堆1.
    b. 解釋下面幾個聲明
    char *p[];
    char (*p)[];
    int *fp();
    int (*fp)();

    char *p[]
        常常被錯誤的理解爲指向字符數組的指針。
        正確的是p一個數組,裏面元素是指向字符的指針類型。
    char (*p)[]
        p是指向指向字符數組的指針。
    int *fp()
        常常錯誤理解爲函數指針,該函數返回int類型。
        正確的是fp是一個函數,他返回一個執行int的指針。
    int (*fp)()
        fp是函數指針,該函數返回int類型。
    
    c. 解釋下面的表達式
    *p.f;
    val & mask != 0;
    max = val1 > val2 ? val1 : val2;

    *p.f
        對p去f偏移,作爲指針,然後進行解引用。相當與*(p.f),因爲.的優先級高與*。比較(*p).f。
    val & mask != 0
        相當與val & (mask != 0).
    max = val1 > val2 ? val1 : val2
        相當與 max = (val1 > val2 ? val1 :val2).
    
    d. 一個複雜的聲明

    char *(* c[10])(int **p);
    1. 有兩個小括號,小括號的結合行是自左向右,所以我們先關注第一個小括號,簡化聲明(*c[10])();
        c是一個數組,裏面放10指針,後面緊跟這一個括號,所以這些指針是函數指針。
    2. 關注第二個括號,(int **p)
        顯然p是函數的參數,它是個指向指針的指針。
    3. 這看最前面的*
        char *說明該函數的返回值是一個指向字符的指針。
    4. 這個聲明的意思就是:c是一個數組,裏面有10個函數指針,指向的函數返回指針,指向字符,函數的參數是指向int類型指針的指針。

1.3 優先級順口溜
    醋罈酸味灌
    味落跳福豆

    共44個運算符

    醋-初等,4個: ( ) [ ] -> 指向結構體成員 . 結構體成員
    壇-單目,9個: ! ~ ++ -- -負號 (類型) *指針 &取地址 sizeof長度
    酸-算術,5個: * / % + -減
    味-位移,2個: << >>
    灌-關係,6個: < <= > >= == 等於 != 不等於
    味-位邏,3個: & 按位與 ^ 按位異或 | 按位或
    落-邏輯,2個: && 邏輯與 || 邏輯或
    跳-條件,1個,三目: ? :
    福-賦值,11個: = += -= *= /= %= >>= <<= &= ^= |=
    豆-逗號,1個: ,

    我更推薦在原理上理解以及長時間的使用來掌握,這順口溜是網上剛剛翻到的,覺得挺好,輔助記憶。

2. 結合性
    在標準C語言的文檔裏,對操作符的結合性並沒有作出非常清楚的解釋。一個滿分的回答是:它是仲裁者,在幾個操作符具有相同的優先級時決定先執行哪一個。
    看例子:
    int a, b = 1, c = 2;
    a = b = c;
    這個表達式只有賦值符,這樣優先級就無法幫助我們呢決定哪個操作先執行。如果a = b先執行,然後 b = c執行。那麼a最終取1。如果b = c先執行, a = b後執行,那麼a最終取2。到底哪一個先執行?看結合性,複製的結合性是右至左,所以b = c,然後a = b。
    同級的操作符,結合性相同。如果在計算表達式的值時候需要考慮結合性,那麼最好把這個表達式一分爲二。

3. 參考資料
    《c Traps and Pitfalls》 Andrew Koenig著, ISBN 978-7-115-17179-5
    《c 專家編程》 Peter Van Der Linden 著, ISBN 978-7-115-17180-1
    順口溜 http://blog.sina.com.cn/s/blog_4e64e2290100be0z.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章