默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进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. SQL Server中调用WebService的实例

    尊重原著作:本文转载自http://www.cnblogs.com/icycore/p/3532197.html 1.Ole Automation Procedures 服务器配置选项 当启用 OLE ...

  2. c#操作sqlite

    一.添加选中dll引用如下图 二.下载一个sqlite建表建库工具sqlitedatabasebrowser如下图 三.使用sqlitedatabasebrowser建库建表 四.插入表数据如下图 四 ...

  3. powerdesigner 转换各种数据库SQL

    转各种SQL脚本的步骤 一.

  4. css层叠机制说明

    css通过建立与文档的关联而实施效果.文档结构重要性不言而喻,对于建立良好的内容索引.提高可维护性.较好的可访问性:另,利于css选择器选择.继承机制. 概要地讲,层叠机制是处理对文档上应用样式时解决 ...

  5. zendStudio安装Xdebug项目断点调试

    1,首先安装xdebug插件 传送门 2,配置php.ini文件如下: [XDebug] xdebug.profiler_append = xdebug.profiler_enable = xdebu ...

  6. Java log4j的环境搭建

    一.Log4j是什么? Log4j是Apache的一个开源代码项目,通过使用Log4j,我们可以控制日志信息输出的目的地.最常见的就是输出到控制台或者日志文件.同时,它强大的一点是可以在C.C++等其 ...

  7. slice,substr,substring

    var s = '0123456789';   //slice 遇负数,则此负数值等同于 s.length + (负数) s.slice(3,6); //"345", 从位置3开始 ...

  8. 关于google CDN 在中国访问不了的解决办法

    因原网站的script部分使用了google CDN,导致在中国看不了跟google相关的所有东西 解决方法: 得把google CDN 连接改成其他公司的CDN 例: 修改前:<script ...

  9. 嵌入式平台组件白盒测试gcov、lcov和genhtml 使用指导

    在嵌入式平台上使用了gtest白盒测试工具,覆盖了被测函数,但是不知道自己测试的效果如何,测试行覆盖率.函数覆盖率,分支覆盖率的数据. 便开始研究gcov这个代码覆盖率工具能否使用,来检查白盒测试的效 ...

  10. UML-类图,包图

    UML构造设计模型   一.类图  二.包图   三.组件图   四.部署图   一.类图     1.类:类由三格表示:类名,类的属性,类的操作              类名: 首字母大学     ...