走进C标准库(1)——assert.h,ctype.h

默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进C标准库。

自己就是菜鸟一只,第一次具体看C标准库,文章参杂了对《the standard C library》的阅读和对源码的一些个人浅显理解,自己记录一下,日后有机会来看可能有另一番感悟吧。

assert.h

 assert宏定义的两种表达方式:

  #define assert(exp) ((exp) ? (void)0 : _assert(msg))

  #define assert(exp) (void)( (exp) || _assert(msg))

     在《C陷阱与缺陷》一书中有描述关于assert宏实现上的考虑。

     在实现上,我们抛弃了下面这种宏实现的方式:

     #define assert(exp) if(!exp) _assert(msg);

     因为上述这个宏可能会产生某些难于察觉的错误:

     if(x > 0 && y > 0)



         assert(x > y);



     else



         assert(y > x);

     上述代码如果采用该宏就会产生else悬挂的问题,且无法在宏内合理有效消除,很不直观。

     所以,采用一开始的两种assert的宏定义是相对较好的。

ctype.h

1. 发展历程:

  惯用法( if (0 <= c && c <= '9' ) ,使用频繁程序过长且没有利用好重用的代码)  到

  函数区分字符类别( isalpha(c) 调用次数过频,影响了程序的执行时间 ) 到

  宏定义(节约了执行时间,但是会遇到一些问题)

2. 宏定义可能会产生的问题

  • 程序员编写的代码量虽然小,但是编译后的代码量很大
  • 子表达式存在捆绑不紧,可能被分割的问题
  • 参数可能会被执行不被期望的多次(如getc,putc,++,--等)

3. 使用转换表

  字符c编入以_ctype命名的转换表索引中。每个表项的不同位以索引字符为特征。如果任何一个和掩码_XXXMARK相对应的位被设置了,那个字符就在测试的类别中。对所有正确的参数,宏展开成一个紧凑的非零表达式。

 1 #define _UPPER          0x1     /* upper case letter */

 2 #define _LOWER          0x2     /* lower case letter */

 3 #define _DIGIT          0x4     /* digit[0-9] */

 4 #define _SPACE          0x8     /* tab, carriage return, newline, */

 5                                 /* vertical tab or form feed */

 6 #define _PUNCT          0x10    /* punctuation character */

 7 #define _CONTROL        0x20    /* control character */

 8 #define _BLANK          0x40    /* space char */

 9 #define _HEX            0x80    /* hexadecimal digit */

10 

11 #define _LEADBYTE       0x8000                  /* multibyte leadbyte */

12 #define _ALPHA          (0x0100|_UPPER|_LOWER)  /* alphabetic character */

 

  1 unsigned short *_pctype = _ctype+1;     /* pointer to table for char's      */

  2 unsigned short *_pwctype = _ctype+1;    /* pointer to table for wchar_t's   */

  3 

  4 unsigned short _ctype[257] = {

  5         0,                      /* -1 EOF   */

  6         _CONTROL,               /* 00 (NUL) */

  7         _CONTROL,               /* 01 (SOH) */

  8         _CONTROL,               /* 02 (STX) */

  9         _CONTROL,               /* 03 (ETX) */

 10         _CONTROL,               /* 04 (EOT) */

 11         _CONTROL,               /* 05 (ENQ) */

 12         _CONTROL,               /* 06 (ACK) */

 13         _CONTROL,               /* 07 (BEL) */

 14         _CONTROL,               /* 08 (BS)  */

 15         _SPACE+_CONTROL,        /* 09 (HT)  */

 16         _SPACE+_CONTROL,        /* 0A (LF)  */

 17         _SPACE+_CONTROL,        /* 0B (VT)  */

 18         _SPACE+_CONTROL,        /* 0C (FF)  */

 19         _SPACE+_CONTROL,        /* 0D (CR)  */

 20         _CONTROL,               /* 0E (SI)  */

 21         _CONTROL,               /* 0F (SO)  */

 22         _CONTROL,               /* 10 (DLE) */

 23         _CONTROL,               /* 11 (DC1) */

 24         _CONTROL,               /* 12 (DC2) */

 25         _CONTROL,               /* 13 (DC3) */

 26         _CONTROL,               /* 14 (DC4) */

 27         _CONTROL,               /* 15 (NAK) */

 28         _CONTROL,               /* 16 (SYN) */

 29         _CONTROL,               /* 17 (ETB) */

 30         _CONTROL,               /* 18 (CAN) */

 31         _CONTROL,               /* 19 (EM)  */

 32         _CONTROL,               /* 1A (SUB) */

 33         _CONTROL,               /* 1B (ESC) */

 34         _CONTROL,               /* 1C (FS)  */

 35         _CONTROL,               /* 1D (GS)  */

 36         _CONTROL,               /* 1E (RS)  */

 37         _CONTROL,               /* 1F (US)  */

 38         _SPACE+_BLANK,          /* 20 SPACE */

 39         _PUNCT,                 /* 21 !     */

 40         _PUNCT,                 /* 22 "     */

 41         _PUNCT,                 /* 23 #     */

 42         _PUNCT,                 /* 24 $     */

 43         _PUNCT,                 /* 25 %     */

 44         _PUNCT,                 /* 26 &     */

 45         _PUNCT,                 /* 27 '     */

 46         _PUNCT,                 /* 28 (     */

 47         _PUNCT,                 /* 29 )     */

 48         _PUNCT,                 /* 2A *     */

 49         _PUNCT,                 /* 2B +     */

 50         _PUNCT,                 /* 2C ,     */

 51         _PUNCT,                 /* 2D -     */

 52         _PUNCT,                 /* 2E .     */

 53         _PUNCT,                 /* 2F /     */

 54         _DIGIT+_HEX,            /* 30 0     */

 55         _DIGIT+_HEX,            /* 31 1     */

 56         _DIGIT+_HEX,            /* 32 2     */

 57         _DIGIT+_HEX,            /* 33 3     */

 58         _DIGIT+_HEX,            /* 34 4     */

 59         _DIGIT+_HEX,            /* 35 5     */

 60         _DIGIT+_HEX,            /* 36 6     */

 61         _DIGIT+_HEX,            /* 37 7     */

 62         _DIGIT+_HEX,            /* 38 8     */

 63         _DIGIT+_HEX,            /* 39 9     */

 64         _PUNCT,                 /* 3A :     */

 65         _PUNCT,                 /* 3B ;     */

 66         _PUNCT,                 /* 3C <     */

 67         _PUNCT,                 /* 3D =     */

 68         _PUNCT,                 /* 3E >     */

 69         _PUNCT,                 /* 3F ?     */

 70         _PUNCT,                 /* 40 @     */

 71         _UPPER+_HEX,            /* 41 A     */

 72         _UPPER+_HEX,            /* 42 B     */

 73         _UPPER+_HEX,            /* 43 C     */

 74         _UPPER+_HEX,            /* 44 D     */

 75         _UPPER+_HEX,            /* 45 E     */

 76         _UPPER+_HEX,            /* 46 F     */

 77         _UPPER,                 /* 47 G     */

 78         _UPPER,                 /* 48 H     */

 79         _UPPER,                 /* 49 I     */

 80         _UPPER,                 /* 4A J     */

 81         _UPPER,                 /* 4B K     */

 82         _UPPER,                 /* 4C L     */

 83         _UPPER,                 /* 4D M     */

 84         _UPPER,                 /* 4E N     */

 85         _UPPER,                 /* 4F O     */

 86         _UPPER,                 /* 50 P     */

 87         _UPPER,                 /* 51 Q     */

 88         _UPPER,                 /* 52 R     */

 89         _UPPER,                 /* 53 S     */

 90         _UPPER,                 /* 54 T     */

 91         _UPPER,                 /* 55 U     */

 92         _UPPER,                 /* 56 V     */

 93         _UPPER,                 /* 57 W     */

 94         _UPPER,                 /* 58 X     */

 95         _UPPER,                 /* 59 Y     */

 96         _UPPER,                 /* 5A Z     */

 97         _PUNCT,                 /* 5B [     */

 98         _PUNCT,                 /* 5C \     */

 99         _PUNCT,                 /* 5D ]     */

100         _PUNCT,                 /* 5E ^     */

101         _PUNCT,                 /* 5F _     */

102         _PUNCT,                 /* 60 `     */

103         _LOWER+_HEX,            /* 61 a     */

104         _LOWER+_HEX,            /* 62 b     */

105         _LOWER+_HEX,            /* 63 c     */

106         _LOWER+_HEX,            /* 64 d     */

107         _LOWER+_HEX,            /* 65 e     */

108         _LOWER+_HEX,            /* 66 f     */

109         _LOWER,                 /* 67 g     */

110         _LOWER,                 /* 68 h     */

111         _LOWER,                 /* 69 i     */

112         _LOWER,                 /* 6A j     */

113         _LOWER,                 /* 6B k     */

114         _LOWER,                 /* 6C l     */

115         _LOWER,                 /* 6D m     */

116         _LOWER,                 /* 6E n     */

117         _LOWER,                 /* 6F o     */

118         _LOWER,                 /* 70 p     */

119         _LOWER,                 /* 71 q     */

120         _LOWER,                 /* 72 r     */

121         _LOWER,                 /* 73 s     */

122         _LOWER,                 /* 74 t     */

123         _LOWER,                 /* 75 u     */

124         _LOWER,                 /* 76 v     */

125         _LOWER,                 /* 77 w     */

126         _LOWER,                 /* 78 x     */

127         _LOWER,                 /* 79 y     */

128         _LOWER,                 /* 7A z     */

129         _PUNCT,                 /* 7B {     */

130         _PUNCT,                 /* 7C |     */

131         _PUNCT,                 /* 7D }     */

132         _PUNCT,                 /* 7E ~     */

133         _CONTROL,               /* 7F (DEL) */

134         /* and the rest are 0... */

135 };

 

 1 #define isalpha(_c)     ( _pctype[_c] & (_UPPER|_LOWER) )

 2 #define isupper(_c)     ( _pctype[_c] & _UPPER )

 3 #define islower(_c)     ( _pctype[_c] & _LOWER )

 4 #define isdigit(_c)     ( _pctype[_c] & _DIGIT )

 5 #define isxdigit(_c)    ( _pctype[_c] & _HEX )

 6 #define isspace(_c)     ( _pctype[_c] & _SPACE )

 7 #define ispunct(_c)     ( _pctype[_c] & _PUNCT )

 8 #define isalnum(_c)     ( _pctype[_c] & (_UPPER|_LOWER|_DIGIT) )

 9 #define isprint(_c)     ( _pctype[_c] & (_BLANK|_PUNCT|_UPPER|_LOWER|_DIGIT) )

10 #define isgraph(_c)     ( _pctype[_c] & (_PUNCT|_UPPER|_LOWER|_DIGIT) )

11 #define iscntrl(_c)     ( _pctype[_c] & _CONTROL )
#define _tolower(_c)    ( (_c)-'A'+'a' )

#define _toupper(_c)    ( (_c)-'a'+'A' )

 

4. 转换表可能遇到的问题

  这种方法的弊端是,对于某些错误的参数,宏会产生错误的代码。如果一个宏的参数不在它的定义域内,那么执行这个宏时,它就会访问转换表之外的存储空间。

  如当测试某些比较生僻的字符代码时,若符号位被置为,那么参数会是一个负数,在函数的定义域之外。

  对于EOF符号,也要慎重处理。

  书上貌似没有提对于转换表实现方式的遇到问题的解决方案 -_-|||

5. 区域设置

  当区域设置改变时,我们的字符分类也可能会发生相应的改变。

6.静态存储空间

  库可以使用指向表的指针的可写的静态存储空间,但我们不能在程序中不同控制线程中共享一个相同的数据对象。

  上面的实现没有使用静态存储空间。

7.实践的实现中都是使用宏的吗?

不小心看到mingw的实现并不是用的宏,代码如下:

#define __ISCTYPE(c, mask)  (MB_CUR_MAX == 1 ? (_pctype[c] & mask) : _isctype(c, mask))

__CRT_INLINE int __cdecl __MINGW_NOTHROW isalnum(int c) {return __ISCTYPE(c, (_ALPHA|_DIGIT));}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isalpha(int c) {return __ISCTYPE(c, _ALPHA);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW iscntrl(int c) {return __ISCTYPE(c, _CONTROL);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isdigit(int c) {return __ISCTYPE(c, _DIGIT);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isgraph(int c) {return __ISCTYPE(c, (_PUNCT|_ALPHA|_DIGIT));}

__CRT_INLINE int __cdecl __MINGW_NOTHROW islower(int c) {return __ISCTYPE(c, _LOWER);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isprint(int c) {return __ISCTYPE(c, (_BLANK|_PUNCT|_ALPHA|_DIGIT));}

__CRT_INLINE int __cdecl __MINGW_NOTHROW ispunct(int c) {return __ISCTYPE(c, _PUNCT);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isspace(int c) {return __ISCTYPE(c, _SPACE);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isupper(int c) {return __ISCTYPE(c, _UPPER);}

__CRT_INLINE int __cdecl __MINGW_NOTHROW isxdigit(int c) {return __ISCTYPE(c, _HEX);}

使用了内联函数的实现,相对于宏更加安全了,另外把预处理的工作交给了编译器,让编译器在代码量和代码效率间自动进行抉择。

 

你可能感兴趣的:(assert)