zoukankan      html  css  js  c++  java
  • 走进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);}

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

    就算黑夜也有星光。
  • 相关阅读:
    C# 线程之间切换
    工厂方法(创建型)
    单例模式(创建型)
    HTTP请求超时
    命令模式
    Asp.Net Core EF Migrations(二)
    Asp.Net Core EF Migrations
    Vue父子组件之间的通讯(学习笔记)
    数组的方法(笔记)
    Vue-router入门
  • 原文地址:https://www.cnblogs.com/shijiezhenmei/p/3652960.html
Copyright © 2011-2022 走看看