默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进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 >  && y > )

         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相对应的位被设置了,那个字符就在测试的类别中。对所有正确的参数,宏展开成一个紧凑的非零表达式。

 #define _UPPER          0x1     /* upper case letter */
#define _LOWER 0x2 /* lower case letter */
#define _DIGIT 0x4 /* digit[0-9] */
#define _SPACE 0x8 /* tab, carriage return, newline, */
/* vertical tab or form feed */
#define _PUNCT 0x10 /* punctuation character */
#define _CONTROL 0x20 /* control character */
#define _BLANK 0x40 /* space char */
#define _HEX 0x80 /* hexadecimal digit */ #define _LEADBYTE 0x8000 /* multibyte leadbyte */
#define _ALPHA (0x0100|_UPPER|_LOWER) /* alphabetic character */
 unsigned short *_pctype = _ctype+;     /* pointer to table for char's      */
unsigned short *_pwctype = _ctype+; /* pointer to table for wchar_t's */ unsigned short _ctype[] = {
, /* -1 EOF */
_CONTROL, /* 00 (NUL) */
_CONTROL, /* 01 (SOH) */
_CONTROL, /* 02 (STX) */
_CONTROL, /* 03 (ETX) */
_CONTROL, /* 04 (EOT) */
_CONTROL, /* 05 (ENQ) */
_CONTROL, /* 06 (ACK) */
_CONTROL, /* 07 (BEL) */
_CONTROL, /* 08 (BS) */
_SPACE+_CONTROL, /* 09 (HT) */
_SPACE+_CONTROL, /* 0A (LF) */
_SPACE+_CONTROL, /* 0B (VT) */
_SPACE+_CONTROL, /* 0C (FF) */
_SPACE+_CONTROL, /* 0D (CR) */
_CONTROL, /* 0E (SI) */
_CONTROL, /* 0F (SO) */
_CONTROL, /* 10 (DLE) */
_CONTROL, /* 11 (DC1) */
_CONTROL, /* 12 (DC2) */
_CONTROL, /* 13 (DC3) */
_CONTROL, /* 14 (DC4) */
_CONTROL, /* 15 (NAK) */
_CONTROL, /* 16 (SYN) */
_CONTROL, /* 17 (ETB) */
_CONTROL, /* 18 (CAN) */
_CONTROL, /* 19 (EM) */
_CONTROL, /* 1A (SUB) */
_CONTROL, /* 1B (ESC) */
_CONTROL, /* 1C (FS) */
_CONTROL, /* 1D (GS) */
_CONTROL, /* 1E (RS) */
_CONTROL, /* 1F (US) */
_SPACE+_BLANK, /* 20 SPACE */
_PUNCT, /* 21 ! */
_PUNCT, /* 22 " */
_PUNCT, /* 23 # */
_PUNCT, /* 24 $ */
_PUNCT, /* 25 % */
_PUNCT, /* 26 & */
_PUNCT, /* 27 ' */
_PUNCT, /* 28 ( */
_PUNCT, /* 29 ) */
_PUNCT, /* 2A * */
_PUNCT, /* 2B + */
_PUNCT, /* 2C , */
_PUNCT, /* 2D - */
_PUNCT, /* 2E . */
_PUNCT, /* 2F / */
_DIGIT+_HEX, /* 30 0 */
_DIGIT+_HEX, /* 31 1 */
_DIGIT+_HEX, /* 32 2 */
_DIGIT+_HEX, /* 33 3 */
_DIGIT+_HEX, /* 34 4 */
_DIGIT+_HEX, /* 35 5 */
_DIGIT+_HEX, /* 36 6 */
_DIGIT+_HEX, /* 37 7 */
_DIGIT+_HEX, /* 38 8 */
_DIGIT+_HEX, /* 39 9 */
_PUNCT, /* 3A : */
_PUNCT, /* 3B ; */
_PUNCT, /* 3C < */
_PUNCT, /* 3D = */
_PUNCT, /* 3E > */
_PUNCT, /* 3F ? */
_PUNCT, /* 40 @ */
_UPPER+_HEX, /* 41 A */
_UPPER+_HEX, /* 42 B */
_UPPER+_HEX, /* 43 C */
_UPPER+_HEX, /* 44 D */
_UPPER+_HEX, /* 45 E */
_UPPER+_HEX, /* 46 F */
_UPPER, /* 47 G */
_UPPER, /* 48 H */
_UPPER, /* 49 I */
_UPPER, /* 4A J */
_UPPER, /* 4B K */
_UPPER, /* 4C L */
_UPPER, /* 4D M */
_UPPER, /* 4E N */
_UPPER, /* 4F O */
_UPPER, /* 50 P */
_UPPER, /* 51 Q */
_UPPER, /* 52 R */
_UPPER, /* 53 S */
_UPPER, /* 54 T */
_UPPER, /* 55 U */
_UPPER, /* 56 V */
_UPPER, /* 57 W */
_UPPER, /* 58 X */
_UPPER, /* 59 Y */
_UPPER, /* 5A Z */
_PUNCT, /* 5B [ */
_PUNCT, /* 5C \ */
_PUNCT, /* 5D ] */
_PUNCT, /* 5E ^ */
_PUNCT, /* 5F _ */
_PUNCT, /* 60 ` */
_LOWER+_HEX, /* 61 a */
_LOWER+_HEX, /* 62 b */
_LOWER+_HEX, /* 63 c */
_LOWER+_HEX, /* 64 d */
_LOWER+_HEX, /* 65 e */
_LOWER+_HEX, /* 66 f */
_LOWER, /* 67 g */
_LOWER, /* 68 h */
_LOWER, /* 69 i */
_LOWER, /* 6A j */
_LOWER, /* 6B k */
_LOWER, /* 6C l */
_LOWER, /* 6D m */
_LOWER, /* 6E n */
_LOWER, /* 6F o */
_LOWER, /* 70 p */
_LOWER, /* 71 q */
_LOWER, /* 72 r */
_LOWER, /* 73 s */
_LOWER, /* 74 t */
_LOWER, /* 75 u */
_LOWER, /* 76 v */
_LOWER, /* 77 w */
_LOWER, /* 78 x */
_LOWER, /* 79 y */
_LOWER, /* 7A z */
_PUNCT, /* 7B { */
_PUNCT, /* 7C | */
_PUNCT, /* 7D } */
_PUNCT, /* 7E ~ */
_CONTROL, /* 7F (DEL) */
/* and the rest are 0... */
};
 #define isalpha(_c)     ( _pctype[_c] & (_UPPER|_LOWER) )
#define isupper(_c) ( _pctype[_c] & _UPPER )
#define islower(_c) ( _pctype[_c] & _LOWER )
#define isdigit(_c) ( _pctype[_c] & _DIGIT )
#define isxdigit(_c) ( _pctype[_c] & _HEX )
#define isspace(_c) ( _pctype[_c] & _SPACE )
#define ispunct(_c) ( _pctype[_c] & _PUNCT )
#define isalnum(_c) ( _pctype[_c] & (_UPPER|_LOWER|_DIGIT) )
#define isprint(_c) ( _pctype[_c] & (_BLANK|_PUNCT|_UPPER|_LOWER|_DIGIT) )
#define isgraph(_c) ( _pctype[_c] & (_PUNCT|_UPPER|_LOWER|_DIGIT) )
#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标准库(1)——assert.h,ctype.h的更多相关文章

  1. 走进C标准库(3)——"stdio.h"中的getc和ungetc

    接前文. 再来看看getc和ungetc的实现.在看这两个函数的实现之前,我们先来想一想这两个函数分别需要做的工作. int getc(FILE *stream) 说明:函数getc从stream指向 ...

  2. 走进C标准库(8)——"string.h"中函数的实现相关字符串操作函数

    我的strcat: char *strcat(char *dest,char *src) { char * reval = dest; while(*dest) dest++; while(*src) ...

  3. 走进C标准库(2)——"stdio.h"中的fopen函数

    其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ...

  4. C++标准库头文件<bits/stdc++.h>

    在使用GNU GCC Compiler的时候,你可以包含一个头文件<bits/stdc++.h>,便可以使用C++中的各种标准库,而不用一个一个包含进来. 这在acm比赛中是一种常用的做法 ...

  5. 走进C标准库(4)——"stdio.h"中的putc

    花了点时间把园子弄得好看了点,现在继续. 函数名: putc 功  能: 输出一字符到指定流中 用  法: int putc(int ch, FILE *stream); #define _putc_ ...

  6. 走进C标准库(5)——"stdio.h"中的其他部分函数

    函数介绍来自:http://ganquan.info/standard-c/ 函数名: freopen 功  能: 替换一个流 用  法: FILE *freopen(char *filename, ...

  7. 走进C标准库(6)——"string.h"中函数的实现memchr

    我写的memchr: void *memchr(const void *buf, char ch, unsigned count){ unsigned ; while(*(buf++) != ch & ...

  8. 走进C标准库(7)——"string.h"中函数的实现memcmp,memcpy,memmove,memset

    我的memcmp: int memcmp(void *buf1, void *buf2, unsigned int count){ int reval; while(count && ...

  9. C语言笔记 14_标准库&assert&ctype&errno&float&limits

    C 标准库 <assert.h> 简介 C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息. 已定义的宏 ass ...

随机推荐

  1. Ubuntu 13.10 下安装node

    1.首先更新Ubuntu在线包:sudo apt-get update && sudo apt-get dist-upgrade, 2.默认Ubuntu已经安装python的,具体版本 ...

  2. Hadoop学习资料收集

    1.漫画HDFS工作原理  http://blog.csdn.net/netcoder/article/details/7442779 2.马哥教育 http://mageedu.blog.51cto ...

  3. sfs

    http://tieba.baidu.com/p/3397811202 http://mooc.guokr.com/post/610664/ http://home.ustc.edu.cn/~boj/ ...

  4. php 数据结构 hash表

    hash表 定义 hash表定义了一种将字符组成的字符串转换为固定长度(一般是更短长度)的数值或索引值的方法,称为散列法,也叫哈希法.由于通过更短的哈希值比用原始值进行数据库搜索更快,这种方法一般用来 ...

  5. UML-状态图,顺序图,活动图

    一.编写用例文档      1.用例的内容:   用例编号   用例名  执行者  前置条件  后置条件  基本路径  扩展路径  字段列表  业务规则                         ...

  6. python发布与共享

    1.新建.py文件,并将代码拷贝到.py文件中 def listItems(items): for item in items : if isinstance(item,list): listItem ...

  7. LDA Gibbs Sampling

    注意:$\alpha$和$\beta$已知,常用为(和LDA EM算法不同) 1.   为什么可用 LDA模型求解的目标为得到$\phi$和$\theta$ 假设现在已知每个单词对应的主题$z$,则可 ...

  8. Android:实现仿 美团/淘宝 多级分类菜单效果

    本例要实现的是诸如美团/淘宝/百度糯米 多级分类菜单效果.当分类数量许多时能够考虑採用两级分类.而诸如美团这样的表现方式是一个不错的选择. 首先上效果图:      主要代码: 1. PopupWin ...

  9. POJ 2029 DP || 暴力

    在大矩形中找一个小矩形 使小矩形包括的*最多 暴力或者DP  水题 暴力: #include "stdio.h" #include "string.h" int ...

  10. jquery Ztree v3.5 实例2 自定义显示在节点前的图片

    显示效果如下: 代码如下: <html> <head><title></title></head> <script type=&quo ...