走进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);}

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

就算黑夜也有星光。
原文地址:https://www.cnblogs.com/shijiezhenmei/p/3652960.html