運算式 (expression、表示式、計算式)

參考

運算式

在程式內用許多的變數以及常數來儲存或是代表一些資料, 我們常常需要計算這些資料經過加減乘除或是 AND,OR 邏輯運算之後的結果, 例如:

所有的運算式都是由運算子 (operator, 算符)運算元 (operand)括號組合起來的。

運算子(算符)

在 C 程式中運算子分為:

  1. 算術

  2. 比較

  3. 邏輯

  4. 條件

  5. 其它

幾大類的運算子, 其中又分為二元 (binary) 的運算子及單元 (unary) 的運算子,

  1. 二元運算子:需要左右兩個運算元參與其運算,例如: a + b, a && b

  2. 單元運算子:只需要一個運算元參與其運算,例如: -a, !flag, ++b

各類運算子基本使用方法請參考課本

  1. 算術 pp 192~197

  2. 比較 pp 198~199

  3. 邏輯 pp 200~201

  4. 位元邏輯 pp 202~204

  5. 條件 pp 204~206

注意:比較運算是利用減法來完成的, 相關的型態轉換可以參考減法。

基本運算原則

  1. 值 (value)

    每一個運算子會作用在其運算元上並產生一值 (value)

    例如:

    double a; a=3.5 運算式的值為 3.5 a + 4 運算式的值為 7.5 int b=10; !b 運算式的值為 0 double a=3.5; !a 運算式的值為 0 -a 運算式的值為 -3.5 a=3.5; a-- 運算式的值為 3.5 a=3.5; --a 運算式的值為 2.5

  2. 運算順序

    一個運算式中可以有多個運算子 (及其作用的運算元), 其運算之順序由

    1. 相同運算子的結合規則 (associativity)
    2. 不同運算子的優先順序 (precedence)

    來決定, 請參考課本第 208 及第 209 頁。

    例如:

  3. 小括號

    運算式中運算子的運算順序可以用小括號來更改 例如: (a + b) * c 先做 a + b 再做 3 * c

  4. 副作用 (side effects)

    大部份的運算子都不會去改變其運算元變數內儲存的數值, 可是少部份的運算子除了計算一個結果數值之外, 還會改變參與運算變數內的數值, 例如:

    注意:

    1. 在同一個運算式中不要讓某一變數參與兩個有 side effect 的運算以免因為 side effect 動作的順序而影響運算式的結果。

      例如:

        ++i + i--

    2. 甚至要避免有 side effect 的變數在運算式中,例如:

        y/2 - (++y + 3)

    3. 結果無法預期 (在不同的編譯器裡可能有不同的結果),

    4. 建議:能避免者儘量避免。

  5. 共同用一個符號 (operator overloading)

    C 語言中很多運算子是共同用一個符號的, 它們所代表的意義與動作不同,例如:

    程式中都只寫個 '+' 號而已, 編譯器究竟如何分辨它們呢?? 其實編譯器完全靠運算元的型態來分辨, 例如:

運算式中資料型態的轉換

  1. 自動的 (或說隱藏的 Implicit) 型態轉換

    前一個例子中

    為浮點之加法, 實際上編譯器自動將整數變數 x 內存放的資料轉換為倍精準浮點數 (double), 並將常數 3.5 以倍精準浮點數 (double)表示, 如此方可執行浮點之加法。

  2. 強制的 (或說表面的 Explicit) 型態轉換 (type coersion)

    上面範例與下例是完全一樣的

    此時程式設計者為了避免混淆, 自己加入 (double) 這樣子的運算子, 確保 CPU 將變數 x 資料取出後會先將之轉換為 double 型態, 再進行浮點相加的運算。

  3. C程式中何時會有隱藏的型態轉換呢??

    1. 算術運算式中
        char 或 short 或 int + char或 short 或 int ===> int + int long + char 或 short 或 int ===> long + long float + float 或 double ===> double + double

    2. 設定運算子 '='
        char x; short 或 int 或 long 或 float 或 double y; x = (char) y; int x; short 或 long 或 float 或 double y; x = (int) y; ...

    3. 函式呼叫時

    資料流失 (data loss)

    變數內資料型態轉換時有可能造成變數內儲存的資料改變, (精確度降低),例如:

    1. 浮點數轉換為整數:

        float -> char, float -> int, float -> long,
        double -> char, double -> int, double -> long,

      都會損失所有小數點後的資料, 如果數字太大超過該整數型態可以表示的最大值時, 超過的位元也會不見, 在執行時出現這兩種狀況你的程式都會假裝沒事一樣地繼續下去, 因此你自己在寫這樣子的程式時要特別小心。

      在做這樣子的型態自動轉換時, 許多編譯器都會給你警告 (warning), 告訴你資料的精確度會降低, 如果你做強制性的型態轉換的話就不會有警告訊息了。

    2. 倍精準浮點轉為浮點數:

        double -> float

      小數點後的精確度會從十進位的 15 位元降為 8 位元, 此種情況不會出現任何編譯警告或是執行錯誤, 若是超過目的浮點數所能表示的最大數字的話會有執行錯誤, 程式會中斷掉。

    3. long -> short 或是 long -> char 或是 short -> char

      若是來源變數內的資料超過目的變數型態所能表示的最大數字的話, 不會產生任何執行時的錯誤, 但是超過的位元會自動消失, 會造成程式邏輯的錯誤。

    程式設計課程 首頁
    by Pei-yih Ting
    E-mail: pyting@cs.ntou.edu.tw