在C語言中,有這樣幾個函數: linux
int isalnum(c) //檢查c是不是字母或數字 int isalpha(c) //檢查c是不是字母 int iscntrl(c) // 檢查c是否控制字符(其ASCII碼在0和0x1F之間,數值爲 0-31) int isdigit(c) //檢測是不是數字 int isgraph(c) //檢查c是否可顯示字符(其ASCII碼在ox21到ox7E之間),不包括空格 int islower(c) int isprint(c) //檢查c是不是可打印字符(包括空格),其ASCII碼在ox20到ox7E之間 int ispunct(c) //檢查c是不是標點字符(不包括空格),即除字母,數字和空格之外的全部可打印字符 int isspace(c) //檢查c是不是空格符和跳格符(控制字符)或換行符 int isupper(c) int isxdigit(c) //檢查c是不是一個16進制數學字符(即0-9,或A-F,或a-f)
通常人的實現方法是用宏定義的方法來實現這寫函數,好比對於int isdigit()函數: git
#define isdigit(c) ((c)>=’0’&&(c)<=’9’)
這樣定義使函數簡潔,使用宏定義省掉了函數調用的開銷,提升了效率。 數組
咱們來看看linux系統下是如何實現的: 函數
#define _U 0x01 /* upper */ #define _L 0x02 /* lower */ #define _D 0x04 /* digit */ #define _C 0x08 /* cntrl */ #define _P 0x10 /* punct */ #define _S 0x20 /* white space (space/lf/tab) */ #define _X 0x40 /* hex digit */ #define _SP 0x80 /* hard space (0x20) */ extern unsigned char _ctype[]; extern char _ctmp; #define isdigit(c) ((_ctype+1)[c]&(_D)) unsigned char _ctype[] = {0x00, /* EOF */ _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */這種方法是用映射的方法,將 ASCII 碼值映射到 _ctype 數組中的每一項。例如 字符‘0’~‘9’對應的ASCII碼爲48~57,映射到上面的_ctype數組相應的位置全是_D,_D&_D爲真,這樣就能判斷出參數c的值是否是數字字符。
另外我在這裏時對於#define isdigit(c) ((_ctype+1)[c]&(_D)) 函數中爲何有_ctype+1不瞭解,這裏若_ctype+1則指向數組的第二個元素_C,爲何要這樣呢? 編碼
這是由於linux大師們在定義字符時把EOF也定義進去了,而EOF的值爲0,多定義了這個元素,並且把他定義在第一位,因此要跳過這一位而從第一個元素開始。還有就是NULL/0其實也是一個控制字符,因此在int
iscntrl(c)函數中若是傳進實參爲NULL,返回值是1的。 spa
我在VS2008裏進行試驗,其代碼爲: 指針
char word[]="chengdu"; printf("%c",(word+1)[1]);結果顯示爲「e」。也就是說,(word+1)做爲一個指針指向word字符串的第二個值。或者說,在數組中,數組名其實就是一個指針,其驗證方法以下:
char word[]="chengdu"; printf("%c",*(word+1));
顯示結果爲「h」。 code
Linux中這幾個函數典型的運用了空間換時間的辦法,其精華之處在於,對不一樣種類的字符進行了分類,並使用惟一的二進制來進行標識。這些用法相信通常的人是想不出來的,而這也正體現出大師們的大師之處。看來有時間仍是要多看linux內核的代碼,從中領悟出大師們的編碼藝術思想。 orm