再談資料型態轉換 (cast)

以下三種狀況,C 會自動做資料型態轉換:

  1. 當變數或常數被當做函式的參數,要傳遞給函式的時候。 如果參數的資料型態與函式所宣告的不合,會自動先做轉換,再傳遞。 例如 atan() 宣告的參數是 double 型態, 但是呼叫
        printf("%.14f\n", 4*atan(1));
    
    也可以,得到的答案是
        3.14159265358979
    
  2. 當二元運算符號的兩邊 (兩個運算元) 資料型態不同的時候, 會轉換成一樣的型態,再做計算。轉換的規則,簡言之,如下:
    1. 若其中一個運算元是 long double,則將另一個轉換成 long double
    2. 否則,若其中一個運算元是 double,則將另一個轉換成 double
    3. 否則,若其中一個運算元是 float,則將另一個轉換成 float
    4. 否則,將 charshort 都轉換成 int
    5. 若其中一個運算元是 long,則將另一個轉換成 long
    所謂二元運算符號,基本上就是 + - * / 四則運算。
  3. = 兩邊的資料型態不同時, 會將右邊的變成左邊的。這種情況我們以前已經見過許多次。 例如 int2char.c 便是。

如果有必要的話,可以強迫做資料型態轉換,稱為 casting。 所謂 casting 並沒有定義新的指令,只要將 C 的資料型態寫在括號裡, 就形成了一個 casting 指令, 它的意義是將 casting 指令後面的第一個變數或常數, 改成括號內的資料型態。 例如 123 原本是 int 型態的常數, 用 (unsigned char) 123 強迫它變成 unsigned char 型態的常數。 再例如 floor(13.0/2) 的值,本來是 double 型態, 用 (int) floor(13.0/2) 強迫它變成 int 型態。 在 數學函式 那一節中,我們曾說,您不可以直接寫

    printf("%d  %d\n", ceil(-3.78), floor(-3.78));
這是因為 printf() 不會自動做資料型態的轉換。 現在我們知道,可以改寫成
    printf("%d  %d\n", (int) ceil(-3.78), (int) floor(-3.78));

以下我們計算 1/3 並輸出小數點下 32 位。我們知道這是個循環小數, 每個小數都應該是 3。但是,因為 1.0/3 內定以 double 資料型態計算, 只能表達大約 16 位十進制的有效數字,所以當我們要求小數點下 32 位時, 可能會輸出荒腔走板的答案。 但是,如果強迫將常數 1.0 的資料型態轉換為 long double, 則常數 3 也會變成 long double, 然後除法就以 long double 的方式來計算。 (casting 的優先序高於除法。) 因此,使用 %.32Lf 就會輸出正確的答案。


#include <stdio.h>
main() {
    printf("1/3 = %.32f\n", 1.0/3);
    printf("1/3 = %.32Lf\n", (long double) 1.0/3);
}

前面的 printf 指令也可以改寫成
    printf("1/3 = %.32Lf\n", 1.0L/3);

由於 casting 的優先序高於 + - % * /, 所以 (long double) 1/3 會先將 1 轉換,再做 / 計算。 小心,(int) 5.0/9(int) (5.0/9) 的結果雖然相同, 但是計算的程序卻不相同。

習題

  1. 以下兩個指令各會輸出什麼?為什麼?
        printf("%d\n", (int) 5.0/9*9);
        printf("%d\n", (int) (5.0/9*9));
    

[ 前一節 ]‧[ 後一節 ]‧[ 回目錄 ]



注意:此處所有文件均為原著,個別的版權宣告日後會一一公布, 整體版面設計亦尚未完成。但仍請勿抄襲文字與圖片,以免觸犯著作權法。

Created: May 7, 2000
Last Revised: May 14, 2000
© Copyright 2000 Wei-Chang Shann 單維彰

shann@math.ncu.edu.tw