%32
在ASCII编码系统中,小写字母和大写字母范围都没有越过“对齐”边界。
这就是为什么位0x20
是同一字母的大写/小写版本之间唯一的区别。
如果不是这种情况,则您需要添加或减去0x20
,而不仅是切换,对于某些字母,可以进行进位来翻转其他更高的位。(而且不会有一个单一的操作可以切换,并且首先检查字母字符会比较困难,因为您不能| = 0x20来强制lcase。)
相关的纯ASCII技巧:您可以通过将小写字母强制为小写c |= 0x20
然后检查(unsigned)是否可以检查字母ASCII字符c - 'a' <= ('z'-'a')
。因此,只需3个操作:针对常数25的OR + SUB + CMP。当然,编译器知道如何(c>='a' && c<='z')
为您优化成这样的asm,因此,您最多应该c|=0x20
自己完成这一部分。自己做所有必要的转换是很不方便的,特别是要解决对signed的默认整数提升int
。
unsigned char lcase = y|0x20;
if (lcase - 'a' <= (unsigned)('z'-'a')) { // lcase-'a' will wrap for characters below 'a'
// c is alphabetic ASCII
}
// else it's not
另请参见将C ++中的字符串转换为大写(toupper
仅SIMD字符串用于ASCII,使用该检查为XOR屏蔽操作数。)
以及如何访问char数组并将小写字母更改为大写字母,反之亦然
(带有SIMD内部函数的C,以及字母ASCII字符的标量x86 asm大小写翻转,其他都保持不变。)
仅当在检查char
向量中的s 均未设置高位之后,使用SIMD手动优化某些文本处理(例如SSE2或NEON)时,这些技巧才最有用。(因此,所有字节都不是单个字符的多字节UTF-8编码的一部分,该编码可能具有不同的大写/小写倒数)。如果找到任何内容,则可以针对这16个字节的块或字符串的其余部分退回到标量。
甚至在ASCII范围内的某些字符上toupper()
或tolower()
某些字符上产生的语言区域超出该范围,尤其是土耳其语,即Iı和İi。 在这些语言环境中,您需要进行更复杂的检查,或者可能根本不尝试使用此优化。
但是在某些情况下,允许您使用ASCII而不是UTF-8,例如,带有LANG=C
(POSIX语言环境)的Unix实用程序,不是en_CA.UTF-8
或不是。
但是,如果可以验证它的安全性,则toupper
中等长度的字符串可以比toupper()
在循环中调用(例如5x)快得多,最后我使用Boost 1.58进行了测试,其速度比每个字符boost::to_upper_copy<char*, std::string>()
都愚蠢得多dynamic_cast
。
@
为`^ 32
。