今天看了一眼nginx的源码,发现里有两个字母大小写转换的宏,乍一看有点不知所云,感觉这种写法有点高级~
#define ngx_tolower(c) (char)((c >= 'A' && c <= 'Z') ? (c | 0x20) : c) #define ngx_toupper(c) (char)((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
核心的方法是两个位运算
- 大写转小写
c | 0x20 - 小写转大写
c & ~0x20
在C语言里面字符是使用ASCII码来表示的,比如A对应的ASCII码是65,a对应的ASCII码是97,常规的将A变成a的方法只需要将A减去32即可,反之将a转换成A只需要加上32即可。
在这里0x20是16进制数32,是的,非常巧合,这里也是32。
c | 0x20是大写转换小写,大写字母的ASCII码会比对应的小写ASCII码要大32,所以这里的c|0x20本质上是在c的基础上加上了32。当然这样看起来不是很直观,从二进制的角度看起来就会变得很直观。
1000001 // 65 A 1100001 // 97 a 0100000 // 32 0x20
可以发现,A和a的二进制只相差一位,所以只需要改变这一位,就可以完成转换,而32对应的二进制的1恰好可以做到这一点。
|或运算可以把有差别的那一位变成1
&~ 与运算加上取反可以把有差别的那一位变成0
如果你对位运算还不是很熟,可以看一下下面这篇推文。
