C 程式設計/ctype.h
在 C 程式語言的 ANSI C 標準庫中,標頭檔案 ctype.h 包含字元分類函式的宣告。
早期在 Unix 下使用 C 語言的工具匠們開始以驚人的速度開發習語來將字元分類為不同的型別。例如,在 ASCII 字元集中,以下測試可以識別字母
if ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z')
但是,此習語不一定適用於其他字元集,如 EBCDIC。
很快,程式中就充斥著類似上述測試,甚至更糟,幾乎與上述測試相同的測試。程式設計師可以以多種不同的方式編寫相同的習語,這會減慢理解速度並增加出錯的機會。
不久後,這些習語就被中的函式取代了<ctype.h>.
與上面的示例不同,字元分類例程不是以比較測試的方式編寫的。在大多數 C 庫中,它們是以靜態表查詢的方式編寫的,而不是宏或函式。
例如,可以建立一個包含 256 個 8 位整數的陣列,並將其排列為位域,其中每個位對應於字元的特定屬性,例如 isdigit、isalpha。如果整數的最低有效位對應於 isdigit 屬性,則程式碼可以這樣編寫
#define isdigit(x) (TABLE[x] & 1)
早期版本的 Linux 使用了類似第一個程式碼示例的潛在錯誤方法
#define isdigit(x) ((x) >= '0' && (x) <= '9')
如果以下情況,這可能會導致問題x有副作用——例如,如果呼叫isdigit(x++)或isdigit(run_some_program()). 不會立即顯而易見的是,對isdigit的引數進行了兩次求值。出於這個原因,通常使用基於表的方。
<ctype.h> 包含十二個字元分類函式的原型。除了 isdigit 和 isxdigit 之外,所有這些函式都是特定於語言環境的;它們的執行行為可能會隨著語言環境的更改而更改。
| 測試 | 以 int isfunc(int); 的形式對 true 返回非零數,對 false 返回零。 |
|---|---|
isalnum |
測試字母數字字元 |
isalpha |
測試字母字元 |
isblank |
測試空白字元(C99 中新增) |
iscntrl |
測試控制字元 |
isdigit |
測試數字。不特定於語言環境。 |
isgraph |
測試圖形字元,不包括空格字元。 |
islower |
測試小寫字母字元 |
isprint |
測試可列印字元,包括空格字元。 |
ispunct |
測試標點符號字元 |
isspace |
測試任何空白字元 |
isupper |
測試大寫字母字元 |
isxdigit |
測試十六進位制數字。不特定於語言環境。 |
| 字元轉換 | 以 int tofunc(int); 的形式返回轉換後的字元,除非它不是字母。 |
tolower |
將字元轉換為小寫字母 |
toupper |
將字元轉換為大寫字母 |
單一 Unix 規範版本 3 添加了類似於上述的函式
isascii |
測試引數是否在 0 到 127 之間 |
toascii |
將字元轉換為 ASCII |
標準規定(§7.4-1)
- 在所有情況下,引數都是一個 int,其值應可表示為一個 unsigned char 或等於宏 EOF 的值。如果引數具有任何其他值,則行為未定義。
不幸的是,許多程式設計師忘記了 char 型別可能是帶符號的或無符號的,具體取決於實現。如果 char 型別是有符號的,則從 char 到 int 的隱式轉換可能會生成負值,從而導致未定義的行為。這通常意味著如果引數用作查詢表的索引,它將訪問正確表之外的區域,甚至可能導致程式崩潰。
使用 char 引數的正確方法是在檢查 EOF 條件後先將其轉換為 unsigned char。
getchar、getc 和 fgetc 返回的 int 型別值保證在 unsigned char(或 EOF)的範圍內,因此在這些情況下不需要轉換。