引言
C 标准库的 ctype.h 头文件提供了一些函数,可用于测试和映射字符,其中有两个函数,int tolower(int c)该函数把大写字母转换为小写字母,int toupper(int c),该函数把小写字母转换为大写字母。那么它们底层的原理是什么呢?能不能用一个方法就实现大写字母转小写,小写字母转大写呢?
字母大小写转换
ASCLL码
我们知道,ASCLL码使用7位数编码了128个字符,其中字母'a'-'z'是97到122,字母'A'到'Z'是65到90,想要判断一个字符的类型,或者将一个字符的大写转换为对应的小写都要运用这个ASCLL码表。
tolower和toupper的实现
我们参考这里的代码实现:
www.aospxref.com/android-12.… 如下:
static inline int islower(unsigned ch) { return (ch - 'a') < 26; }
static inline int isupper(unsigned ch) { return (ch - 'A') < 26; }
18 int LLVM_LIBC_ENTRYPOINT(tolower)(int c) {
19 if (internal::isupper(c))
20 return c + 'a' - 'A';
21 return c;
22 }
18 int LLVM_LIBC_ENTRYPOINT(toupper)(int c) {
19 if (internal::islower(c))
20 return c + 'A' - 'a';
21 return c;
22 }
可以看到,上面的逻辑是很朴素的,判断是否是小写,就使用当前值减去'a'的值,判断是否小于26;判断大写的逻辑也相似。
在转换为小写时,先判断是大写才转换,小写直接返回。如果是大写,则需要加上'a'与'A'的差(很明显,这里加了一个正数);转换大写的逻辑类似。
能否使用一个函数来完成这个判断加转换的工作?
首先,我们注意到,'a'与'A'的差值是97-65=32,是一个比较特殊的数2^5;
其次,我们来看看,这两个字符的二进制表示:
字符 | int值 | 二进制表示 |
'a' | 97 | 0110 0001 |
'A' | 65 | 0100 0001 |
'a'-'A' | 32 | 0010 0000 |
'z' | 122 | 0111 1010 |
'Z' | 90 | 0101 1010 |
这里,可以很明显地看出来,中间的32和上下两个值的关系:异或关系
即:97 = 65 ^ 32,同时65 = 97 ^ 32;
这样我们就可以改写一下转变大小写的函数,只是我们的函数将大写转为小写,小写转为大写,总是反过来,如下:
int reverseChar(int c) {
return c ^ (1 << 5);
}
将原来的加减法加判断,转换为了位运算操作。你体会到位运算的奥妙了吗?
实际上,我们要理解,异或运算相当于不进位的加法,这样一想,对ASCLL编码的操作其实都是可以用异或操作来代替加法的
标签:return,运算,--,大写,int,大小写,小写,转换,函数 From: https://blog.51cto.com/u_15830688/5834980