在没读<ctype.h>的源码之前,我一直以为我们平时用的isalnum、isdigit、isalpha等这些函数,是靠判断写出来的。

比如:

int isdigit(int c){
return ( ((char)c >= '0' && (char)c <='9') ? 1 : 0 );
}

在没有阅读源码之前,可能大多数人都会这么做,其实这样做是正确的。但是我在看了源码之后,才发现标准库并不是这样来实现这些函数的。是靠转换表来高效的实现的。

这是<ctype.h>的字符类别(第一次用Xmind6这玩意...)
内容:
isalnum(int c): 判别所有isalpha或者isdigit判别为真的字符。
isalpha(int c): 判别所有isupper或者islower判别为真的字符,或者那些实现定义的字符集中的iscntrl、isdigit、ispunct、和isspace判别都不为真的字符。
iscntrl(int c); 判别所有的控制字符。
isdigit(int c); 判别所有的十进制数字字符。
isgraph(int c); 判别除空格(' ')之外的所有打印字符。
islower(int c); 判别所有的小写字母。
isprint(int c); 判别包括空格(' ')在内的所有打印字符。
ispunct(int c); 判别除空格(' ')和isalnum判别为真的字符之外的所有打印字符。
isspace(int c); 判别所有标准的空白字符,或者由实现定义的字符集中isalnum判别为假的字符。标准空白字符有:空格(' ')、换页('\f')、换行('\n')、回车('\r')、水平制表符('\t')和垂直制表符('\v')。
isupper(int c); 判别所有的大写字母。
isxdigit(int c); 判别所有的十六进制数字字符。
tolower(int c); 函数tolower把一个大写字母转换为小写字母。
toupper(int c); 函数toupper把一个小写字母转换为大写字母。
实现:大部分好的实现都把EOF值定义为-1,所以转换表中元素的数目一定比字符类型所能表示的所有字符的数目多1。所以一个转换表中一定至少包含257个元素。<ctype.h>
#ifndef _CTYPE
#define _CTYPE /* _Ctype code bits */
#define _XA 0X200/* extra alphabetic */
#define _XS 0x100 /* extra space */
#define _BB 0x80 /* BEL, BS, etc. */
#define _CN 0x40 /* CR, FF, HT, NL, VT */
#define _DI 0x20 /* '0' - '9' */
#define _LO 0x10 /* 'a' - 'z' */
#define _PU 0x08 /* punctuation */
#define _SP 0x04 /* space */
#define _UP 0x02 /* 'A' - 'Z' */
#define _XD 0x01 /* '0' - '9', 'A' - 'F', 'a' - 'f' */ /* declarations */ int isalnum(int), int alpha(int),int iscntrl(int), int isdigit(int);
int isgraph(int), int islower(int),int isprint(int), int ispunct(int);
int isspace(int), int isupper(int),int isxdigit(int);
int tolower(int), inttoupper(int); extern const short *_Ctype, *_Tolower, *_Toupper; /* macro */ #define isalnum(c)(_Ctype[(int)c] & (_DI | _LO | _UP | _XA))
#define isalpha(c)(_Ctype[(int)c] & (_LO | _UP | _XA))
#define iscntrl(c)(_Ctype[(int)c] & (_BB | _CN))
#define isdigit(c)(_Ctype[(int)c] & (_DI))
#define isgraph(c)(_Ctype[(int)c] & (_DI | _LO | _PU | _UP | _XA))
#define islower(c)(_Ctype[(int)c] & (_LO))
#define isprint(c)(_Ctype[(int)c] & (_DI | _LO | _PU | _SP | _UP | _XA))
#define ispunct(c)(_Ctype[(int)c] & (_PU))
#define isspace(c)(_Ctype[(int)c] & (_CN | _SP | _XS))
#define isupper(c)(_Ctype[(int)c] & (_UP))
#define isxdigit(c)(_Ctype[(int)c] & (_XD))
#define tolower(c)_Tolower[(int)c]
#define toupper(c)_Toupper[(int)c] #endif /* _CTYPE */
还有这些函数的文件就不写了,举个例子,其他的都一样:int isalnum (int c)
{
return (_Ctype[(int)c] & (_DI | _LO | _UP | _XA));
}

xctyoe.c 文件:

在这个转换表里的前面,我们还看到了三个宏定义:

#define  XDI  (_DI  | _XD)
#define XLO (_LO | _XD)
#define XUP (_UP | _XD)

加上这个三个宏定义后,我们在判断十六进制和十进制的'0' - '9'时,和判断十六进制的'A' - 'F'或'a' - 'f'和英文字母时,都可以得到正确的结果。

另外,xctype.c的最下面有个const指针,指向了转换表的第二个元素,因此转换表的第一个元素存储的就是EOF了。

下面来看看tolower和toupper函数,它们也各有一张转换表:

xtolower.c :

xupper.c :

在xtolower.c中,我们看到从ASCII码值为65开始,是小写字母,从97开始,依然是小写字母,所以这张表,当tolower函数传进去的是大写字母时,被转换为对应的小写字母,如果传进去的是小写字母,则不变。同理,xtoupper.c也是这样。至于表中剩余其它的值,我们不用管。

我们可能会想,自己写像如开头那样的函数实现也可以啊,转化表一做感觉代码挺长的,其实,<ctype.h>里做成转换表而不是直接实现每个函数,是因为数组的访问速度非常快,效率高。而且三张表就可以实现所有的函数的实现!

《C标准库》——之<ctype.h>的更多相关文章

  1. 彻底弄清c标准库中string.h里的常用函数用法

    在我们平常写的c/c++程序,一些算法题中,我们常常会用到c标准库中string.h文件中的函数,这些函数主要用于处理内存,字符串相关操作,是很有用的工具函数.而且有些时候,在笔试或面试中也会出现让你 ...

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

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

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

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

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

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

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

    默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进C标准库. 自己就是菜鸟一只,第一次具体看C标准库,文章参杂了对<the standard C library>的阅读和对源码的一些 ...

  6. C 非标准库(conio.h)

    所谓的 C 标准库(C standard library),是指在 ISO C 或者 POSIX 标准中定义的: POSIX is a superset(超集) of the standard C l ...

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

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

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

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

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

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

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

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

随机推荐

  1. C#解析Json(多方法解析Json 一)

    解析:{'id':'4028d80858053bed0158053ef7a50001','sl':0.0,'sfyfz':'0','zwjyzsbh':'1000001600000018'} 1.新建 ...

  2. HandleErrorAttribute 特性使用

    public class EwHandleErrorAttribute : HandleErrorAttribute { public override void OnException(Except ...

  3. 精通JS 笔记

    一,javascript数据类型:undefined,null,boolean,number,string,object 五种加一种复杂类型. 注意大小写,区分大不写函数:functiontypeof ...

  4. SQL CAST, CONVERT 比较

    本文转自:http://www.cnblogs.com/denylau/archive/2010/12/01/1893371.html if (@StartTime > @EndTime)    ...

  5. 创建条形码图像易用的控制字符编码功能的条形码控件Native Crystal Reports Barcode Generator

    Native Crystal Reports Barcode Generator是一个对象,它可以很容易地被嵌入到一个Crystal Report中用于创建条形码图像.一旦此条形码被安装在一个报表中, ...

  6. Gmail新版截图曝光 你还能认得出来吗?

    Gmail即将迎来巨大的改变.据外媒消息,目前Google正在测试新的网页版Gmail.要知道从Gmail推出以来还从未进行过如此大的改动. 新版Gmail中,界面相比之前,采用了更加扁平话的设计,整 ...

  7. 微软.NET Framework 4.5.2 RTM正式版

    今天,微软.NET开发团队发布.NET Framework 4.5.2 RTM正式版.新版框架继续高度兼容现有的.NET Framework 4.4.5.4.5.1等版本,该版本框架与旧版的.NET ...

  8. JavaScript 之 走马灯

    1.原理分析:首先截取字符串的最后一位用Last表示,再截取剩余字符串用Rest表示,拼接字符串Last + Rest, 此事字符串是不会动的,还需要一个函数setInterval(javascrip ...

  9. 机器翻译(noip2010)

    分析:该题是经典的队列题目,直接用队列实现就可以.如果数据范围大一些的话还可hash判重! 这可以说是一道送分的题目,但是还有粗心的学生会在这里失分,主要原因是数组的范围定义的不合适,因为空间足够用, ...

  10. Smart Card Filesystem