《C标准库》——之<ctype.h>
在没读<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>的更多相关文章
- 彻底弄清c标准库中string.h里的常用函数用法
		在我们平常写的c/c++程序,一些算法题中,我们常常会用到c标准库中string.h文件中的函数,这些函数主要用于处理内存,字符串相关操作,是很有用的工具函数.而且有些时候,在笔试或面试中也会出现让你 ... 
- 走进C标准库(8)——"string.h"中函数的实现相关字符串操作函数
		我的strcat: char *strcat(char *dest,char *src) { char * reval = dest; while(*dest) dest++; while(*src) ... 
- 走进C标准库(3)——"stdio.h"中的getc和ungetc
		接前文. 再来看看getc和ungetc的实现.在看这两个函数的实现之前,我们先来想一想这两个函数分别需要做的工作. int getc(FILE *stream) 说明:函数getc从stream指向 ... 
- 走进C标准库(2)——"stdio.h"中的fopen函数
		其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ... 
- 走进C标准库(1)——assert.h,ctype.h
		默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进C标准库. 自己就是菜鸟一只,第一次具体看C标准库,文章参杂了对<the standard C library>的阅读和对源码的一些 ... 
- C 非标准库(conio.h)
		所谓的 C 标准库(C standard library),是指在 ISO C 或者 POSIX 标准中定义的: POSIX is a superset(超集) of the standard C l ... 
- 走进C标准库(4)——"stdio.h"中的putc
		花了点时间把园子弄得好看了点,现在继续. 函数名: putc 功 能: 输出一字符到指定流中 用 法: int putc(int ch, FILE *stream); #define _putc_ ... 
- 走进C标准库(5)——"stdio.h"中的其他部分函数
		函数介绍来自:http://ganquan.info/standard-c/ 函数名: freopen 功 能: 替换一个流 用 法: FILE *freopen(char *filename, ... 
- 走进C标准库(6)——"string.h"中函数的实现memchr
		我写的memchr: void *memchr(const void *buf, char ch, unsigned count){ unsigned ; while(*(buf++) != ch & ... 
- 走进C标准库(7)——"string.h"中函数的实现memcmp,memcpy,memmove,memset
		我的memcmp: int memcmp(void *buf1, void *buf2, unsigned int count){ int reval; while(count && ... 
随机推荐
- 开源性能测试工具--Jmeter介绍+安装
			一. Apache JMeter介绍 1. Apache JMeter是什么Apache JMeter 是Apache组织的开放源代码项目,是一个100%纯Java桌 ... 
- 【NOIP模拟_54测试】【并查集】【二进制】【搜索】【区间序列类】
			第一题 Mushroom的序列 大意: 给一个序列,求一段连续最长区间满足:最多改变一个数,使得区间是严格的上升子序列. 解: 直接扫描一遍,记一个最长上升子序列编号.然后从每一个编号为1 的点来判断 ... 
- IT公司100题-5-查找最小的k个元素
			问题描述: 输入n 个整数,输出其中最小的k 个. 例如输入8, 7, 6, 5, 4, 3, 2, 1这8 个数字,则最小的3 个数字为3, 2, 1. 分析: 时间复杂度O(nlogn)方法: ... 
- No module ata_piix found的解决方法
			在一台as4u6的机器上升级内核到2.6.18时,最好make install的时候报了一个WARNING: No module ata_piix found for 2.6.18, 开始没有在意,重 ... 
- 事件函数SetEvent、PulseEvent与WaitForSingleObject详解
			系统核心对象中的Event事件对象,在进程.线程间同步的时候是比较常用,发现它有两个出发函数,一个是SetEvent,还有一个PulseEvent, 两者的区别是: SetEvent为设置事件对象为有 ... 
- Windows Azure 实操 —— 迁移本地SharePoint服务器到Azure
			博客地址 http://blog.csdn.net/foxdave 注意:如果你是第二代虚拟机,那就别看这个了,老老实实在Azure上重新创建吧,Azure不支持第二代虚拟机. 写在之前,对Azure ... 
- ODI 12.1.3发布,提升支持大数据的能力
			此次发布的ODI新版本,目的是更好的支持当前市场上的大数据平台. 大数据基因在不改变ODI工作效率的情况下,ODI增加了越来越多的数据源集成能力.ODI是在Oracle平台上标准的E-LT工具,事实上 ... 
- equals() 与 hashcode() 的区别与联系
			两者都是从Object类继承的方法,Object中equals方法比较的是this和参数传进来的对象的引用地址是否相同,这样的话,equals返回值为true的必要充分条件就是两者指向同一个对象,那么 ... 
- 【iOS开发】企业版证书($299)In-House方式发布指南   (转)
			一.明确几个概念 1.企业版IDP:即iOS Development Enterprise Program.注意是$299/Year那种,并不是$99/Year的那种. 2.In House:是只企业 ... 
- 码表由来:ascll码-Gbk2312-GBK-Unicode-UTF-8
			码表ascll码-Gbk2312-GBK-Unicode-UTF-8, ascll是基本的标准码表,GB2312是中文码表,GBK是扩展之后的码表,Unicode是国际通用码表,UTF-8是优化后的U ... 
