assert.h
assert宏定義的兩種表達方式:
#define assert(exp) ((exp) ? (void)0 : _assert(msg))
#define assert(exp) (void)( (exp) || _assert(msg))
ctype.h
1. 發展歷程:
慣用法( if (0 <= c && c <= '9' ) ,使用頻繁程序過長且沒有利用好重用的代碼) 到
函數區分字符類別( isalpha(c) 調用次數過頻,影響了程序的執行時間 ) 到
宏定義(節約了執行時間,但是會遇到一些問題)
2. 宏定義可能會產生的問題
3. 使用轉換表
字符c編入以_ctype命名的轉換表索引中。每個表項的不同位以索引字符為特征。如果任何一個和掩碼_XXXMARK相對應的位被設置了,那個字符就在測試的類別中。對所有正確的參數,宏展開成一個緊湊的非零表達式。
_UPPER 0x1 /* upper case letter */ _LOWER 0x2 /* lower case letter */ _DIGIT 0x4 /* digit[0-9] */ _SPACE 0x8 /* tab, carriage return, newline, */ _PUNCT 0x10 /* punctuation character */ _CONTROL 0x20 /* control character */ _BLANK 0x40 /* space char */ _HEX 0x80 /* hexadecimal digit */ _LEADBYTE 0x8000 /* multibyte leadbyte */ _ALPHA (0x0100|_UPPER|_LOWER) /* alphabetic character */
unsigned *_pctype = _ctype+; unsigned *_pwctype = _ctype+; unsigned _ctype[] = , _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _SPACE+_CONTROL, _SPACE+_CONTROL, _SPACE+_CONTROL, _SPACE+_CONTROL, _SPACE+_CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _CONTROL, _SPACE+_BLANK, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _DIGIT+_HEX, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _UPPER+_HEX, _UPPER+_HEX, _UPPER+_HEX, _UPPER+_HEX, _UPPER+_HEX, _UPPER+_HEX, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _UPPER, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _LOWER+_HEX, _LOWER+_HEX, _LOWER+_HEX, _LOWER+_HEX, _LOWER+_HEX, _LOWER+_HEX, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _LOWER, _PUNCT, _PUNCT, _PUNCT, _PUNCT, _CONTROL, };
isalpha(_c) ( _pctype[_c] & (_UPPER|_LOWER) ) isupper(_c) ( _pctype[_c] & _UPPER ) islower(_c) ( _pctype[_c] & _LOWER ) isdigit(_c) ( _pctype[_c] & _DIGIT ) isxdigit(_c) ( _pctype[_c] & _HEX ) isspace(_c) ( _pctype[_c] & _SPACE ) ispunct(_c) ( _pctype[_c] & _PUNCT ) isalnum(_c) ( _pctype[_c] & (_UPPER|_LOWER|_DIGIT) ) isprint(_c) ( _pctype[_c] & (_BLANK|_PUNCT|_UPPER|_LOWER|_DIGIT) ) isgraph(_c) ( _pctype[_c] & (_PUNCT|_UPPER|_LOWER|_DIGIT) ) iscntrl(_c) ( _pctype[_c] & _CONTROL )
_tolower(_c) ( (_c)-'A'+'a' ) _toupper(_c) ( (_c)-'a'+'A' )
4. 轉換表可能遇到的問題
這種方法的弊端是,對於某些錯誤的參數,宏會產生錯誤的代碼。如果一個宏的參數不在它的定義域內,那麼執行這個宏時,它就會訪問轉換表之外的存儲空間。
如當測試某些比較生僻的字符代碼時,若符號位被置為,那麼參數會是一個負數,在函數的定義域之外。
對於EOF符號,也要慎重處理。
書上貌似沒有提對於轉換表實現方式的遇到問題的解決方案 -_-|||
5. 區域設置
當區域設置改變時,我們的字符分類也可能會發生相應的改變。
6.靜態存儲空間
庫可以使用指向表的指針的可寫的靜態存儲空間,但我們不能在程序中不同控制線程中共享一個相同的數據對象。
上面的實現沒有使用靜態存儲空間。
7.實踐的實現中都是使用宏的嗎?
不小心看到mingw的實現並不是用的宏,代碼如下:
__ISCTYPE(c, mask) (MB_CUR_MAX == 1 ? (_pctype[c] & mask) : _isctype(c, mask)) __cdecl __MINGW_NOTHROW isalnum( c) { __ISCTYPE(c, (_ALPHA| __cdecl __MINGW_NOTHROW isalpha( c) { __cdecl __MINGW_NOTHROW iscntrl( c) { __cdecl __MINGW_NOTHROW isdigit( c) { __cdecl __MINGW_NOTHROW isgraph( c) { __ISCTYPE(c, (_PUNCT|_ALPHA| __cdecl __MINGW_NOTHROW islower( c) { __cdecl __MINGW_NOTHROW isprint( c) { __ISCTYPE(c, (_BLANK|_PUNCT|_ALPHA| __cdecl __MINGW_NOTHROW ispunct( c) { __cdecl __MINGW_NOTHROW isspace( c) { __cdecl __MINGW_NOTHROW isupper( c) { __cdecl __MINGW_NOTHROW isxdigit( c) { __ISCTYPE(c, _HEX);}
使用了內聯函數的實現,相對於宏更加安全了,另外把預處理的工作交給了編譯器,讓編譯器在代碼量和代碼效率間自動進行抉擇。