单引号

  1. char c;
  2. c = 'a';
  3. c = '1';
  4. c = 'A';

单引号在字符常量时使用,表示单个字符。当在单引号中出现两个及以上字符时或没有字符时,编译出错,且C语言中不允许出现空字符。

在 js 中,下面代码是会打出 false 的,因为 js 语言本质上把字符和数字当成两种不同的基本类型。

  1. function str(){
  2. console.log('a' === 97)
  3. }

在 C语言中,则会打出 true ,因为在C语言中,整数/字符/二进制 都是同样以二进制存储的,处理字符时会先根据 ascll 码来转化为整数进而转化为二进制。

这里就需要字符集的概念给一个变量赋值一个字符时,会先去字符集查找对于的整数去存储,当程序想要表达一个字符时需要拿到根据整数在字符集中对应字符。

‘ \0’ 在字符集中对应的整数就是 0,0 和 ‘ \0’ 在计算机中存储的时候是完全一致的,把一份数据从不同角度观察的结果。

C语言通常将数值常量以及字符常量视为 int 而不是将字符常量视为 char,就会有奇怪的现象 32 位的值赋给 8 位的存储单元。

  1. char a = 'a';

转义字符的三种表达方式:\n,\ + 八进制,\x + 十六进制

双引号

C 语言没有字符串类型但也可以很好地处理字符串,双引号在表示字符串常量时使用,可以表示0到多个字符组成的字符串,允许出现空字符串。

  1. char s1[] = "a";
  2. char s2[] = "a1A";

‘A’ 表示单个字符大写字母A,占用1个字节空间

“A” 表示字符串,该字符串只有1个大写字母A组成,占用2个字节空间,每个字符串末尾自动会加上一个空字符 ‘\0’

ctype.h库

对于判断一个字符是否是某种类型,我们很容易就想到使用遍历的方法,

  1. if('0' <= c && c <= '9')

但是数字的字符是连续的,对于其他的类型比如标点符号需要多个区间判断,这就有点性能过于昂贵了,比如下面判断是否有空格

  1. if(c == ' ' || c == '\t' || c == '\n')

Ascall 表总共有 256 个字符,于是 ctype.h 做法是在内部维护一个转换表,提供我们传入宏的参数作为下标来取到表中的值

  1. #define islower(c) (_Ctype[(int)(c)] & _LO)

由于宏参数没有类型,我们先进行类型转化

  1. static const short ctype_tab[257] = { 0, /* EOF */
  2. _BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
  3. _BB, _CN, _CN, _CN, _CN, _CN, _BB, _BB,
  4. _BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
  5. _BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
  6. _SP, _PU, _PU, _PU, _PU, _PU, _PU, _PU,
  7. _PU, _PU, _PU, _PU, _PU, _PU, _PU, _PU,
  8. XDI, XDI, XDI, XDI, XDI, XDI, XDI, XDI,
  9. XDI, XDI, _PU, _PU, _PU, _PU, _PU, _PU,
  10. _PU, XUP, XUP, XUP, XUP, XUP, XUP, _UP,
  11. _UP, _UP, _UP, _UP, _UP, _UP, _UP, _UP,
  12. _UP, _UP, _UP, _UP, _UP, _UP, _UP, _UP,
  13. _UP, _UP, _UP, _PU, _PU, _PU, _PU, _PU,
  14. _PU, XLO, XLO, XLO, XLO, XLO, XLO, _LO,
  15. _LO, _LO, _LO, _LO, _LO, _LO, _LO, _LO,
  16. _LO, _LO, _LO, _LO, _LO, _LO, _LO, _LO,
  17. _LO, _LO, _LO, _PU, _PU, _PU, _PU, _BB,
  18. };
  19. const short *_Ctype = &ctype_tab[1];

至于 _LO 就是宏中预先对每种类型设置的唯一的一个数,比如小写字母就是 _LO

当判断 ‘a’ 是否为小写字母的时候,使用宏 islower,通过宏替换,也即执行(_Ctype[(int)(c)] & _LO)

预处理之后,假设当前的 c 是 ‘a’ 那么变成了: (_Ctype[(int)(‘a’)] & _LO) 字符’a’的值为97所以接下来便是: (_Ctype[97] & _LO)

_Ctype[97]的转换宏是 _LO ,通过查_Ctype 转换表,_LO 的值又是 0x10,所以最后是:(_LO & _LO) ——> 0x10 & 0x10 ——> 1, 说明当前字符为小写字母