ctype.h

ctype.h是c标准函数库中的头文件   定义了一批c语言字符分类函数   (c character classification functions) 用于测试字符是否属于特定的字符类别 ,如字母字符、控制字符等等。既支持单字节   byte字符  也支持宽字符
文件中包含两类字符函数   字符测试函数    例如   int  isxxx(int)   
字符映射函数(转换)   例如    int   toxxx(int)
  1   背景
宏的意外
a 宏可能比函数调用执行得快   但是展开后的代码可能回避函数调用的多几倍    如果你的程序在很多地方扩展宏   程序会很大
b 宏可能会展开为一个子表达式    但是它不像函数调用那样紧凑   所以需要在宏定义中使用圆括号  消除弊端
c 宏展开后某些参数可能执行了不止一次  或者根本就不执行   一个具有副作用的宏参数会导致意外的发生   只有两个c标准库函数getc和putc  使用时可能会产生这种不安全行为的宏
 
转换表
一个宏的集合来代替这些字符分类函数      translation table
例子:   每个宏存在的形式
#define _XXXMASK  0x...
#define isxxx(c) (_Ctyptab[c] &  _XXXMASK)
 
字符c编入以_Ctyptab命名的转换表索引中   每个表项的不同位以索引字符位特征  如果任何一个和掩码_XXXMASK相对应的位被设置了   那个字符就在要测试的类别中   对所有正确的参数  宏展开成一个紧凑的非零表达式
        有弊端
区域设置
转换表仍然是很多字符分类函数的当今实现的基础    他们会为实现者提供高效的宏   
一个c程序总是在“c”区域设置中开始执行   调用函数setlocale可以改变区域设置    当设置改变时    头文件中声明的函数的某些属性就可能改变它的行为
C语言中的区域设置是C标准委员会的发明,当时加进区域设置(相关声明在locale.h中)是为了支持欧洲那里与美国不同的字符集,现在的区域设置同时也支持亚洲字符集。
 
一.标准内容
头文件的内容省略
ctype.h  头文件声明了几个可以用于识别和转换字符的函数
对于所有参数是int类型的情况  参数值可以表示为unsigned char类型  或者和宏EOF的值是相等的   如果参数为其他的值   则它的行为未定义。
这些函数的行为受当前区域设置的影响   当处于c之外的区域设置时   有些函数的某些方面时由实现定义的     
比如
打印字符   指的是由实现定义的字符集的一个元素   每个打印字符在显式设备上都占据一个打印位置   
控制字符   是实现定义的字符集中不是打印字符的元素
1.字符判断函数
当且仅当参数c的值和函数描述中的一致时才返回非0
isalnum  alphanumeric 的缩写     要求每个名字以字母开头     后面可以使数字或者字母
#include <ctype.h>
int isalnum(int c)
函数isalnum判别所有isalpha或者isdigit 判别为真的字符
 
isalpha alphabetic的缩写  不区分大小写   测试本地字母表中的字母   对于c区域 就是熟悉的26个字母包括大小写
判别所有isupper或者islower判别为真的字符    或者那些实现定义的字符集中的iscntrl  isdigit  ispunct  和isspace判别都不为真的字符     在c区域设置中    只对 isupper或者islower判别为真的字符返回真
iscntrl   控制字符   报警  退格   回车   换页   水平制表符   换行和垂直制表符
isdigit     判别所有十进制     最稳定的函数  之一   只包括10个十进制数字    
例如  
for(value=0;isdigit(*s);++s)
value=value*10+(*s-'0');    简化实现数字转化的代码
isgraph   除空格外的所有打印字符
islower  小写
isprint   包括空格在内的所有打印字符
ispunct 除空格和isalnum判别为真的字符之外的所有打印字符  最好认为标点符号属于图形字符 而不属于字母数字
isspace    空白字符   或者由实现定义的字符集中isalnum判别为假的字符  比较重要    库函数使用此函数来判定把哪些字符作为空格对待   在c区域设置中    此函数用来识别输出到显式设备时    所有改变打印位置   却没有显式图形的字符
isupper  大写   
isxdigit   16进制 不随着区域设置而改变    专门用来识别十六进制数    
在所有的区域设置中   对十六进制转换的代码
#include <ctype.h>
#include <string.h>
...
static const xd[]={"0123456789abcdef}";
static const char xv[]={
0,1.2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11,12,13,14,15};
for(value=0;isxdigit(*s);++s)
value=(value<<4)+xv[strchr(xd,*s)-xd];
}
          注意溢出的检查
 
 
2.字符大小写转换函数
tolower   大变小       也可将哪些没有大写形式的字母和大小写形式都没有的字母处理为小写字母     简单的加上或者减去一个常量就能把大写字母转换为对应的小写字母   仅仅适用于ASCII和EBCDIC这两种常用的字符集    c标准并没有此要求
toupper 小变大     同上    仅仅功能相反
 
二   头文件的使用
此头文件中声明的函数      可以用来对字符进行判断和转换    这些字符由 fgetc    getc    getchar等函数读入   
需要声明数据对象为整形
如果参数值不是上述的函数读入   需要谨慎    头文件中的函数只对stdio.h中定义的EOF值和unsigned char类型可以代表的值正确工作    仅当基本c字符集的字符表示为char类型的时候   他们为正值
 
字符类别
字符分类函数定义的字符类别有:
a 数字   0-9  十进制
b 十六进制   0-f
c 小写字母    a-z     在c区域设置外可能会加上其他的字符
d 大写字母 A-Z
e 字母  小写字母或者大写字母   在c区域设置外可能会加上其他的字符
f 字母数字   字母或者数字
g 图形字符   占据一个打印位置   输出到显式设备时可见的字符
h 标点符号   非字母数字的图形字符   至少包括表示c源程序文本的29个符号
i 打印字符   图形字符或者空格符
j 空格    空格字符  和5个标准的运动控制字符   换页符 FF   换行符  NL     回车符  CR     水平制表符  HT   垂直制表符 VT    在c区域设置外可能会加上其他的字符
k 控制字符   5个标准的运动字符   (j项)    退格符BS   和劲爆符  BEL   加上其他可能的字符中的一个字符

上图说明了字符分类函数之间的联系

矩形框中的字符都属于基本c字符集      表示任意的c源文件的字符    
函数名下有一个加号表明这个函数在c区域设置外的区域设置中可以表示附加的字符   
两个加号表明这个函数即使在c区域设置下也可以表示附加的字符
执行字符集可以包含其他分类下的字符    同一个字符只能位于图表中的一个位置    如果是小写字母  那么它也可 以通过集成而属于多个类     但是一个字符不能既是标点符号 有事控制字符
几乎所有的函数都能在区域设置变动的程序中改变行为    只有isdigit和isxdigit保持不变   
区域设置改变
使用字符分类函数增加任何测试  以删除任意的不在分类中的字符
或者   在程序改变它的区域设置为非c区域设置之前   去掉所有独立与区域设置中的判别代码   使他们不会影响程序结果。
 

三  头文件的实现
一个转换表描述了执行字符集的特征   每个函数把它的参数作为表的入口    然后在把选择的表元素和一个唯一的掩码比较来确定参数字符是否在字符类别中
大小由包含的元素个数和每个元素的大小决定的     标准c定义了3中字符类型   char     signed char  和unsigned char
至少需要8位才能表示执行字符集中的所有字符
 
取值范围
每个字符分类函数都接收一个int类型的参数   但是参数值需要在一定的范围内    其中unsigned char 类型所能表示的所有值都是有效的   还有宏EOF所确定的值。    大部分实现都把EOF表示为-1
   8为表示一个字符类型  所以一个转换表一定要包含257个元素
在上图中至少有两个增补的字符集处于c区域之外
函数isalpha可以识别islower和isupper都不能识别的字符
函数sispace可以识别iscntrl和isprint都不能识别的字符
 
共享库 库可以使用指向表的指针的可写的静态存储空间 也就是翻译器必须包含c标准库中的代码  
c标准库中的所有代码都占据一个独立的内存空间
一个链接好并在这个环境中运行的c程序把控制权转移给共享库中的函数 而不是把库中的代码复制到自己的程序中 这样做
的好处是程序更小而且链接得更快
可写的静态存储空间
当一个或者多个函数需要维持一个属于库私有的可写的静态数据对象时,不能在不同的程序或者同一个程序的不同控
制线程之间共享一个相同的数据对象,需要为每一个程序或者线程分配一个唯一的可写的静态数据对象 并且要初始化
操作系统和链接器使用特定的机器系统使共享库工作 有些直接禁用可写的静态存储空间 其他的则要求启用特定的
机器系统来建立 和访问可写的静态存储空间 所以我们必须用一种特殊的方式来编写代码
字符分类函数需要适应区域设置的改变 就需要可写的静态存储空间 一种方法是区域改变时重新写表 另种是改变指
向表的指针 表为只读 从而加快区域设置改变的速度
 
ctype.h 头文件 声明了函数的代码都是围绕3个转换表 3个可写的指针一直指向对应与当前区域设置的表
每个函数都有一个对应的宏 那些定义了分类位的宏名晦涩但是节省空间 可以加速对标准头文件的处理
 
/*ctype.h standard header*/
#ifndef _CTYPE
#define _CTYPE
/*_Ctype code bits*/ 代码位宏定义
 
#define _XA 0x200    /*extra alphabetic*/
#define _BB 0x80 /*BEL,BS,ETC*/
...
...
 
/*declarations*/声明函数和指向表的指针
int isalnum(int),isalpha(int),iscntrl(int)...
extern const short *_Ctype,*_Tolower,*_Toupper;
 
/*macro overrides*/  函数宏
#define isalnum(c) (_Ctype[(int)(c)]&(_DI|_LO|_UP|_XA))
#define isalpha(c) (_Ctype[(int)(c)]&(_LO|_UP|_XA))
...
endif
 
isalnum.c代码
/*isalnum function*/
#include <ctype.h>
int (isalnum)(int c)
{ //测试字符
return (_Ctype[c]&(_DI|_LO|_UP|_XA));
}
 
xtolower.c
/*_Tolower conversion table --ASCII version*/
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#if EOF!=-1||UCHAR_MAX!=255
#error WRONG TOLOWER TABLE
#endif
 
/*static data*/
static const short tolow_tab[257]={
EOF,0x00,0x01,0x02.......,'a','b','c',...,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,'a','b','c','d',...0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82.....0xff
};
const short *_Tolower=&tolow_tab[1];
注意#error指令的使用  保证了只有在假设成立的情况下代码才被正确的翻译   <limits.h>中定义的宏 UCHAR_MAX给出了unsigned char类型所能表示的最大值
xtoupper.c  源代码省略
 
数据对象  _Ctype
xctype.c  所有的字符分类函数都公用一个_Ctype指向的转换表    这个文件就定义了这个表和指针
源代码:
/*_Ctype conversion table -- ASCII version*/
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#if EOF!=-1 || UCHAR_MAX !=255
#error WRONG CTYPE TABLE
#endif
 
/*macros*/
#define XDI (_DI|_XD)
#define XLO(_LO|_XD)
#define XUP(_UP|_XD)
 
/*static data*/
static const short ctyp+tab[257]={0,/*EOF*/
_BB,_BB,_BB,..._CN,_CN..._BB,_BB..._PU,_PU...};
/*rest all match mothing*/
const short *_Ctype=&ctyp_tab[1];
 
 
五  <ctype/h>的测试
 

ctype.h 第2章的更多相关文章

  1. C标准头文件<ctype.h>

    主要包括了一些字符识别和转换函数 字符判断 isalnum() //函数原型 #include<ctype.h> int isalum(int c); 功能:如果输入的字符是字母(alph ...

  2. C 标准库系列之ctype.h

    ctype.h 主要提供了一些函数用以测试字符或字符处理的功能函数:包括字符判断检测.字符转换: 目前ASCII字符可分为以下一些类型,如:大写.小写.字母.数字.十六进制.空白字符.可打印字符.控制 ...

  3. c 头文件<ctype.h>(二)

    测试<ctype.h>函数 #include <stdio.h> #include <ctype.h> int main(){ ; ; i < ; ++i){ ...

  4. c 头文件<ctype.h>(一)

    头文件<ctype.h>中声明了一些测试字符的函数. 每个函数的参数均为int类型,参数的值必须是EOF或可用unsigned char类型表示的字符,函数返回值为int类型. 如果参数c ...

  5. C标准库<ctype.h>实现

    本文地址:http://www.cnblogs.com/archimedes/p/c-library-ctype.html,转载请注明源地址. 1.背景知识 ctype.h是C标准函数库中的头文件,定 ...

  6. 《C标准库》——之<ctype.h>

    在没读<ctype.h>的源码之前,我一直以为我们平时用的isalnum.isdigit.isalpha等这些函数,是靠判断写出来的. 比如: int isdigit(int c){ re ...

  7. C库函数手册(ctype.h)

    ctype.h函数说明:int isalpha(int ch)  若ch是字母('A'-'Z','a'-'z')返回非0值,否则返回0 int isdigit(int ch)  若ch是数字('0'- ...

  8. c语言字符类别测试库函数#include<ctype.h>

    字符类测试<ctype.h> 头文件<ctype.h>中说明了一些用于测试字符的函数.每个函数的变量均为int类型,变量的值必须是EOF或可用unsigned char类型表示 ...

  9. ctype.h库函数

    头文件ctype.h声明了一组用于分类和转换单个字符的函数.所有的函数都接收一个int型的参数,并返回一个int——返回的int可能代表一个字符,也可能代表的是bool值(0为假,非0为真). 你可能 ...

随机推荐

  1. KMP字符串模式匹配详解

    KMP字符串模式匹配详解 http://www.cppblog.com/oosky/archive/2006/07/06/9486.html

  2. Idea 2017注册码

    BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  3. Jenkins怎么启动和停止服务

    笔者没有把Jenkins配置到tomcat中,每次都是用命令行来启动Jenkins.但是遇到一个问题:Jenkins一直是开着的,想关闭也关闭不了.百度了一些资料,均不靠谱(必须吐槽一下百度).于是进 ...

  4. dlopen与dlsym用法

    dlopen和dlsym是用于打开动态链接库中的函数,将动态链接库中的函数或类导入到本程序中: dlopen函数: 功能:打开一个动态链接库 包含头文件: #include <dlfcn.h&g ...

  5. java 中设计模式

    1. 单例模式(一个类只有一个实例) package ch.test.notes.designmodel; /** * Description: 单例模式 (饿汉模式 线程安全的) * * @auth ...

  6. 怎么在webstorm中设置代码模板

    大家都知道webstorm对程序员来说是一个很好用的IDE.我们输入几个关键字,webstorm就会给出提示,大大提高了我们的开发效率,可有时候webstorm的默认设置不能满足我们的个性化代码模板的 ...

  7. c#写出乘法口诀

    显然是显得无聊五分钟写的乘法口诀 static void Main(string[] args)        {            int dq;            int[] array ...

  8. 优化SQL语句的方法

    首先,对于where语句的注意事项: 1.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where nu ...

  9. CPP-基础:C++拷贝构造函数详解

    一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象 ...

  10. ubuntu 16.04 安装node.js 8.x

    引自 https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-16-04#how-to-in ...