C 教材:sizeof 和 ++-- 算子

以下程式計算一個從 stdin 輸入的純文字檔案有幾個字元 (byte),EOF 不算在內。 通常以 int 資料型態來計數。 但是一般的 int 是 32-bit,故最大只能記錄到 231-1。 為了能夠處理很大的檔案,所以宣告計數的資料型態是 long, 如果系統有支援的話,它是 64-bit 的長整數, 最大可以記錄到 263-1。


#include <stdio.h>
 
/* 簡化的 UNIX wc -c 程式,long while 版本  (nc-long.c) */
main() {
   long nc=0;
 
   while (getchar() != EOF)
       ++nc;
   printf("%ld\n", nc);
}

注意,printf 輸出長整數的資料格式是 %ld。 在這個程式裡面,我們根本不需要處理輸入的字元, 所以沒有宣告一個變數來儲存輸入的字元。

我們又看到 ++ 符號。 ++ 運算符號的優先度是 13,右傾。++nn++ 的意義, 在某些場合是不同的。詳情以後再談。

相對有一個 -- 運算符號,優先度也是 13,右傾。 --n; 就是將 n = n - 1; 的意思。

但是某些系統內的 C 編譯程式並不支援長整數。 即使如此,也不見得會在編譯的時候看到任何訊息。 比較保險的方法是,檢查 long 資料型態的含量。 語句是 sizeof(long),回應的值是整數資料型態, 代表 long 的資料含量是幾個 bytes。

如果 long 不夠長 (例如和 int 一樣是四個拜), 還有一個方法是用 double 來計數。 雙精度浮點數並不能真實記錄從 -263 到 263-1 的所有整數,因為畢竟它的底數只有 52 bits。 但是它總是比 32-bit 的 int 有能力記錄更大的整數。

如果要改用 double 來計數,以上的程式應改寫成


#include <stdio.h>
 
/* 簡化的 UNIX wc -c 程式,double while 版本  (nc-double.c) */
main() {
   double nc=0;
 
   while (getchar() != EOF)
       ++nc;
   printf("%.0f\n", nc);
}

注意:(1) printf 輸出雙精度浮點數的資料格式仍然是 %f; (2) 但是,如果 nc 超過了 double 所能忠實表現的整數, 看不到警訊。

以上程式可以用 a.out < file 來執行, 並且可以和 wc -c file 的結果相比對。 結果應該相同才對。 例如可以試試看 a.out < mywc-c1.c。 我們讓 a.out 這個程式檢查它自己的原始碼有幾個字元。

最後,我們再提醒兩件事: 第一,sizeof 就和 longdouble 一樣, 都是 C 的保留字。 換句話說,sizeof() 不是外部函式, 它是 C 本身知道怎麼做的少數幾件事之一。

其次,我們再練習一次 while 語法轉 for 語法。


#include <stdio.h>
 
/* 簡化的 UNIX wc -c 程式,double for 版本  (nc-whfor.c) */
main() {
   double nc=0;
 
   for (; getchar() != EOF;  ++nc);
   printf("%.0f\n", nc);
}

我們看到一個空的 INITIAL 語句,甚至連 STATEMENTS_ 都是空的。 注意,printf() 的退格和 for 在同一層上, 這提醒了讀者,printf()for 的下一個指令, 而非 for 內部的指令。

最後,我們提醒讀者,++-- 只能作用在變數上。 所以,例如 ++3++sizeof(int) 都是錯誤的。 因為,轉換成

    3 = 3 + 1;
    sizeof(int) = sizeof(int) + 1;
這些指令,都是錯誤的。等號 = 的左邊必需是變數,用來儲存等號右邊的執行結果。

習題

  1. 寫一個程式印出來 charintlongfloatdouble 的資料含量。
  2. 舉出一個用 double 無法記錄,但是用 64-bit 的 long 可以記錄的正整數。
  3. 如果 c 是一個 float 型態的資料,卻不慎用 %d 格式來輸出,會有什麼結果?做一個實驗,例如 c = 0.5。 解釋以上結果。
[BCC16-C]
單維彰 (2000/03/30) --- 00/05/18 (單), 03/04/26 (單)
[Prev] [Next] [Up]