ctype

关于C标准库中的ctype.h(阅读《The Standard C Library》)

nrush@2018/10/18
个人学习笔记,若有错误,欢迎交流指正。

1.ctype.h的目的

ctype.h的主要功能是提供对字符进行分类和两个映射函数。

2.字符集相关知识

字符集的种类很多,ASCII仅仅是一种字符集,对于不同地区和用途,字符集无论是数目还是含义的差异都很大,对于C来说其规定了一套基础的标准字符,即这些字符在任何字符集中都应该存在且有相同的含义和功能。这些标准字符包括以下这些:

字母:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ
数字:0123456789abcdefABCDEF(后面的字母仅在16进制数字中出现)
标点:!#%&|/*±?:’";.^<>=
标准运动控制符:\r(回车CR) \n(换行NL) \t(水平制表HT) \v(垂直制表VT) \f(翻页FF)
控制符:\b(退格BS) \a(报警BEL)
空格:" "

备注:在显示字符中标准运动控制字符也被统一认为是空格符即isspace(标准运动控制符)返回为真。

3.ctype.h的函数及源码分析

3.1 函数

函数名功能
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)判断是否为16进制数
int tolower(int c)转化为小写
int toupper(int c)转化为大写

以下是各判断函数的关系图。(摘自《The Standard C Library》)
在这里插入图片描述

3.2 实现分析

源码实现方式是使用转换表对判断字符的类型,对于不同的字符集应当加载不同的转换表。

以下为一种ctype.h的实现方式

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H

/*
 * 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 const 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)
static inline int isdigit(int c)
{
	return '0' <= c && c <= '9';
}
#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)
/* Note: isspace() must return false for %NUL-terminator */
#define isspace(c)	((__ismask(c)&(_S)) != 0)
#define isupper(c)	((__ismask(c)&(_U)) != 0)
#define isxdigit(c)	((__ismask(c)&(_D|_X)) != 0)

#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)

static inline unsigned char __tolower(unsigned char c)
{
	if (isupper(c))
		c -= 'A'-'a';
	return c;
}

static inline unsigned char __toupper(unsigned char c)
{
	if (islower(c))
		c -= 'a'-'A';
	return c;
}

#define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)

/*
 * Fast implementation of tolower() for internal usage. Do not use in your
 * code.
 */
static inline char _tolower(const char c)
{
	return c | 0x20;
}

/* Fast check for octal digit */
static inline int isodigit(const char c)
{
	return c >= '0' && c <= '7';
}

#endif

#endif
// SPDX-License-Identifier: GPL-2.0
/*
 *  linux/lib/ctype.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/ctype.h>
#include <linux/compiler.h>
#include <linux/export.h>

const 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);

4.其它

  • 对标准库的理解,所谓的标准库实际上是一套实现特定功能并能稳定运行的库,其具体实现原理未必是相同的。
  • inline关键字被称为内联函数,使用该关键字的作用是为了提高效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值