Chinaunix
标题:
内核里isprint系列函数的实现
[打印本页]
作者:
karma303
时间:
2017-05-23 07:17
标题:
内核里isprint系列函数的实现
本帖最后由 karma303 于 2017-05-23 07:44 编辑
ctype.h里isxxx()系列的函数,不知道大家常不常用。
我最近在写一个文本解析器。 在写类似 #define IS_SPACE(c) ( strchar("\t\f\n\r ") == true) 的宏时,想起来标准里的这些函数。 就看了看man page, 看了半天,才区分明白。
先集体亮个相:
int isalnum(int c);
int isalpha(int c);
int iscntrl(int c);
int isdigit(int c);
int isgraph(int c);
int islower(int c);
int isprint(int c);
int ispunct(int c);
int isspace(int c);
int isupper(int c);
int isxdigit(int c);
int isblank(int c);
复制代码
有5个函数比较简单:
isupper, islower, isdigit。 分别是大写,小写,数字。
isalpha, isalnum。 分别是字母, (字母与数字)。 alpha的原意是希腊语的第一个字母(A, a), 相当于字母表里的A,a。
有2个函数我不常用到, 忽略掉:
isxdigit, iscntrl。
算了,还是说一下cntrl字符吧。 它们是0~31的ascii码,另外127号ascii也是, 共计34个。 7~13号我们比较熟悉:
\a, \b, \t, \n, \v, \f, \r
复制代码
其中的不少是为早期的打印机而生的, 像\f是换页打印。 \n喂纸。 \r回车, 它还可以把printf送回屏幕行首,也就是把stdout的write操作lseek回行首。这在重度的命令行界面编程时很有用,因为写屏是非seek的。
\a是响一声。 不过现在很多系统都不会响了(包括我的ubuntu)。 据说早期的终端都配有bell,是怕操作员太无聊睡着, 后来终端变小了,就退化为bepper(主板上的蜂鸣器),到现在的虚拟终端,\a的行为就未定义了。
除去这7个,剩余控制字符的有谁在实际工作中遇到,请一定发邮件告诉我。
回到正题,现在就剩下4个了:
int isgraph(int c);
int isprint(int c);
int ispunct(int c);
int isspace(int c);
int isblank(int c);
复制代码
先说isprint()。 它是指32 ~ 126号字符。 除了32号空格键,其它的都是看得见的(图形)字符。
但我不太用这个函数(它能干什么), 所以决定忘掉它。
对我有用的是isgraph, 它包含的正是所有图形字符, 33 ~ 126号, 仅从isprint()里剔除一个空格键。 我们用 if( !isgraph( c) )就可以判定一个空白字符(我在文本解析里, 认为空白和不可见是等价的, 虽然后者的字符集更大)。 不过type.h提供了一个专门的函数, isspace()。 它判定的更精细, 它只认:
\n \r \s \t \v \f
复制代码
这几个字符。
所以总结一下。 128个ascii首先可以分成3部分。
图形字符 93个 isgraph()
控制字符 34个 iscntrl()
空格字符 1个
复制代码
图形字符又可以细分:
图形字符
==> 字母数字 isalnum()
==> 字母 isaplha()
==> 大写 isupper()
==> 小写 islower()
==> 数字 isdigit()
==> 标点符号 ispunct()
复制代码
刚才漏讲的ispunct()现在出现了。 他就是图形字符里,除了字母数字外的所有字符。 punctuation是标点符号的意思。 这里只能理解为广义的标点符号了,因为包含了!@#这些。
还有一个忘说的是isblank(), 因为我觉得它的存在除了混淆视听, 没有任何意义,所以我也决定忘掉它。
最后点题。 不然就要被删帖了。
内核(glibc估计也是)对这些函数的实现, 是基于table的, 而不是类似 ((c) == '\n' || (c) == '\r')。 好处有二: 一是更快, 第二个是避免多次side effect(假如前面的c是个有side effect的表达式)。
下面是2.6.11.12的源码:
/*
* NOTE! This ctype does not handle EOF like the standard C
* library is required to.
*/
#define _U 0x01 /* upper */
#define _L 0x02 /* lower */
#define _D 0x04 /* digit */
#define _C 0x08 /* cntrl */
#define _P 0x10 /* punct */
#define _S 0x20 /* white space (space/lf/tab) */
#define _X 0x40 /* hex digit */
#define _SP 0x80 /* hard space (0x20) */
extern unsigned char _ctype[];
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
复制代码
unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
EXPORT_SYMBOL(_ctype);
复制代码
上面代码的思路很简单,就是建立一个256字节的数组(我们只关心前面128个), 下标正是ascii码, ctype[asscii] 存储的是这个ascii码的属性信息, 是通过手工的硬编码存进去的, 例如, 它是大写字母吗, 是小写子母吗, 是控制字符吗, 是数字吗。。等等。 isxxx函数只要做个位与就得出结果了。
【完】
作者:
_nosay
时间:
2017-05-23 07:59
回复
1#
karma303
作者:
nswcfd
时间:
2017-05-31 10:40
补充一下,isprint主要用在Hexdump里,isprint的字符用自身表示,其它的用.表示,
比如printf '%b' '\x'{0..3}{0..9} | hexdump -C
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2