免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2498 | 回复: 2

[其他] 内核里isprint系列函数的实现 [复制链接]

论坛徽章:
13
程序设计版块每日发帖之星
日期:2016-06-29 06:20:00每日论坛发贴之星
日期:2016-08-14 06:20:00操作系统版块每日发帖之星
日期:2016-08-14 06:20:00每日论坛发贴之星
日期:2016-08-13 06:20:00数据库技术版块每日发帖之星
日期:2016-08-13 06:20:00程序设计版块每日发帖之星
日期:2016-08-13 06:20:00IT运维版块每日发帖之星
日期:2016-08-13 06:20:00每日论坛发贴之星
日期:2016-08-12 06:20:00数据库技术版块每日发帖之星
日期:2016-08-12 06:20:00程序设计版块每日发帖之星
日期:2016-08-12 06:20:00操作系统版块每日发帖之星
日期:2016-08-12 06:20:00综合交流区版块每日发帖之星
日期:2016-08-09 06:20:00
发表于 2017-05-23 07:17 |显示全部楼层
本帖最后由 karma303 于 2017-05-23 07:44 编辑

ctype.h里isxxx()系列的函数,不知道大家常不常用。
我最近在写一个文本解析器。 在写类似 #define IS_SPACE(c) ( strchar("\t\f\n\r ") == true) 的宏时,想起来标准里的这些函数。 就看了看man page, 看了半天,才区分明白。
先集体亮个相:
  1.        int isalnum(int c);
  2.        int isalpha(int c);
  3.        int iscntrl(int c);
  4.        int isdigit(int c);
  5.        int isgraph(int c);
  6.        int islower(int c);
  7.        int isprint(int c);
  8.        int ispunct(int c);
  9.        int isspace(int c);
  10.        int isupper(int c);
  11.        int isxdigit(int c);
  12.        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号我们比较熟悉:
  1. \a, \b, \t, \n, \v,  \f, \r
复制代码
其中的不少是为早期的打印机而生的, 像\f是换页打印。 \n喂纸。 \r回车, 它还可以把printf送回屏幕行首,也就是把stdout的write操作lseek回行首。这在重度的命令行界面编程时很有用,因为写屏是非seek的。
\a是响一声。 不过现在很多系统都不会响了(包括我的ubuntu)。 据说早期的终端都配有bell,是怕操作员太无聊睡着, 后来终端变小了,就退化为bepper(主板上的蜂鸣器),到现在的虚拟终端,\a的行为就未定义了。
除去这7个,剩余控制字符的有谁在实际工作中遇到,请一定发邮件告诉我。


回到正题,现在就剩下4个了:
      
  1.        int isgraph(int c);
  2.        int isprint(int c);
  3.        int ispunct(int c);
  4.        int isspace(int c);
  5.        int isblank(int c);
复制代码
先说isprint()。 它是指32 ~ 126号字符。 除了32号空格键,其它的都是看得见的(图形)字符。
但我不太用这个函数(它能干什么), 所以决定忘掉它。
对我有用的是isgraph, 它包含的正是所有图形字符, 33 ~ 126号, 仅从isprint()里剔除一个空格键。 我们用 if( !isgraph( c) )就可以判定一个空白字符(我在文本解析里, 认为空白和不可见是等价的, 虽然后者的字符集更大)。 不过type.h提供了一个专门的函数, isspace()。 它判定的更精细, 它只认:
  1. \n \r \s \t \v \f
复制代码
这几个字符。

所以总结一下。 128个ascii首先可以分成3部分。
  1. 图形字符  93个  isgraph()
  2. 控制字符  34个   iscntrl()
  3. 空格字符  1个
复制代码
  1. 图形字符又可以细分:
  2. 图形字符
  3.                ==> 字母数字                                                   isalnum()
  4.                                        ==> 字母                                  isaplha()
  5.                                                        ==> 大写                  isupper()
  6.                                                        ==> 小写                  islower()
  7.                                        ==> 数字                                  isdigit()
  8.                ==> 标点符号                                                   ispunct()



复制代码
刚才漏讲的ispunct()现在出现了。 他就是图形字符里,除了字母数字外的所有字符。 punctuation是标点符号的意思。 这里只能理解为广义的标点符号了,因为包含了!@#这些。
还有一个忘说的是isblank(), 因为我觉得它的存在除了混淆视听, 没有任何意义,所以我也决定忘掉它。

最后点题。 不然就要被删帖了。
内核(glibc估计也是)对这些函数的实现, 是基于table的, 而不是类似 ((c) == '\n' || (c) == '\r')。 好处有二: 一是更快, 第二个是避免多次side effect(假如前面的c是个有side effect的表达式)。
下面是2.6.11.12的源码:

  1. /*
  2. * NOTE! This ctype does not handle EOF like the standard C
  3. * library is required to.
  4. */

  5. #define _U        0x01        /* upper */
  6. #define _L        0x02        /* lower */
  7. #define _D        0x04        /* digit */
  8. #define _C        0x08        /* cntrl */
  9. #define _P        0x10        /* punct */
  10. #define _S        0x20        /* white space (space/lf/tab) */
  11. #define _X        0x40        /* hex digit */
  12. #define _SP        0x80        /* hard space (0x20) */

  13. extern unsigned char _ctype[];

  14. #define __ismask(x) (_ctype[(int)(unsigned char)(x)])

  15. #define isalnum(c)        ((__ismask(c)&(_U|_L|_D)) != 0)
  16. #define isalpha(c)        ((__ismask(c)&(_U|_L)) != 0)
  17. #define iscntrl(c)        ((__ismask(c)&(_C)) != 0)
  18. #define isdigit(c)        ((__ismask(c)&(_D)) != 0)
  19. #define isgraph(c)        ((__ismask(c)&(_P|_U|_L|_D)) != 0)
  20. #define islower(c)        ((__ismask(c)&(_L)) != 0)
  21. #define isprint(c)        ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
  22. #define ispunct(c)        ((__ismask(c)&(_P)) != 0)
  23. #define isspace(c)        ((__ismask(c)&(_S)) != 0)
  24. #define isupper(c)        ((__ismask(c)&(_U)) != 0)
  25. #define isxdigit(c)        ((__ismask(c)&(_D|_X)) != 0)
复制代码
  1. unsigned char _ctype[] = {
  2. _C,_C,_C,_C,_C,_C,_C,_C,                        /* 0-7 */
  3. _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                /* 8-15 */
  4. _C,_C,_C,_C,_C,_C,_C,_C,                        /* 16-23 */
  5. _C,_C,_C,_C,_C,_C,_C,_C,                        /* 24-31 */
  6. _S|_SP,_P,_P,_P,_P,_P,_P,_P,                        /* 32-39 */
  7. _P,_P,_P,_P,_P,_P,_P,_P,                        /* 40-47 */
  8. _D,_D,_D,_D,_D,_D,_D,_D,                        /* 48-55 */
  9. _D,_D,_P,_P,_P,_P,_P,_P,                        /* 56-63 */
  10. _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,        /* 64-71 */
  11. _U,_U,_U,_U,_U,_U,_U,_U,                        /* 72-79 */
  12. _U,_U,_U,_U,_U,_U,_U,_U,                        /* 80-87 */
  13. _U,_U,_U,_P,_P,_P,_P,_P,                        /* 88-95 */
  14. _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,        /* 96-103 */
  15. _L,_L,_L,_L,_L,_L,_L,_L,                        /* 104-111 */
  16. _L,_L,_L,_L,_L,_L,_L,_L,                        /* 112-119 */
  17. _L,_L,_L,_P,_P,_P,_P,_C,                        /* 120-127 */
  18. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                /* 128-143 */
  19. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                /* 144-159 */
  20. _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
  21. _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
  22. _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
  23. _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
  24. _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
  25. _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */

  26. EXPORT_SYMBOL(_ctype);
复制代码

上面代码的思路很简单,就是建立一个256字节的数组(我们只关心前面128个), 下标正是ascii码, ctype[asscii] 存储的是这个ascii码的属性信息, 是通过手工的硬编码存进去的, 例如, 它是大写字母吗, 是小写子母吗, 是控制字符吗, 是数字吗。。等等。 isxxx函数只要做个位与就得出结果了。

【完】

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-05-23 07:59 |显示全部楼层
回复 1# karma303

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
发表于 2017-05-31 10:40 |显示全部楼层
补充一下,isprint主要用在Hexdump里,isprint的字符用自身表示,其它的用.表示,
比如printf '%b' '\x'{0..3}{0..9} | hexdump -C
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP