我找到了这段代码
int strlen_my(const char *s) { int len = 0; for(;;) { unsigned x = *(unsigned*)s; if((x & 0xFF) == 0) return len; if((x & 0xFF00) == 0) return len + 1; if((x & 0xFF0000) == 0) return len + 2; if((x & 0xFF000000) == 0) return len + 3; s += 4,len += 4; } }
我很想知道它是如何工作的. ¿任何人都可以解释它是如何工作的?
解决方法
按位AND与1将从另一个操作数中检索位模式.含义,10101& 11111 = 10101.如果该按位AND的结果为0,则我们知道另一个操作数为0.当使用0xFF(1)对单个字节进行AND运算时,结果为0将指示NULL字节.
代码本身在四字节分区中检查char数组的每个字节.注意:此代码不可移植;在另一台机器或编译器上,unsigned int可能超过4个字节.使用uint32_t数据类型来确保32位无符号整数可能会更好.
首先要注意的是,在小端机器上,构成字符数组的字节将以相反的顺序读入无符号数据类型;也就是说,如果当前地址的四个字节是对应于abcd的位模式,则无符号变量将包含对应于dcba的位模式.
第二个是C中的十六进制数常量导致一个int大小的数字,在位模式的小端有指定的字节.这意味着,当使用4字节整数进行编译时,0xFF实际上是0x000000FF. 0xFF00是0x0000FF00.等等.
所以程序基本上是在四个可能的位置寻找NULL字符.如果当前分区中没有NULL字符,它将前进到下一个四字节插槽.
以char数组abcdef为例.在C中,字符串常量总是在末尾有空终止符,因此在该字符串的末尾有一个0x00字节.
它的工作原理如下:
将“abcd”读入unsigned int x:
x: 0x64636261 [ASCII representations for "dcba"]
检查每个字节是否有空终止符:
0x64636261 & 0x000000FF 0x00000061 != 0,0x64636261 & 0x0000FF00 0x00006200 != 0,
并检查其他两个位置;此4字节分区中没有空终止符,因此前进到下一个分区.
将“ef”读入unsigned int x:
x: 0xBF006665 [ASCII representations for "fe"]
注意0xBF字节;这超过了字符串的长度,所以我们从运行时堆栈中读取垃圾.它可能是任何东西.在不允许未对齐访问的计算机上,如果字符串后面的内存不是1字节对齐,则会崩溃.如果字符串中只剩下一个字符,我们将读取两个额外的字节,因此与char数组相邻的内存对齐必须是2字节对齐的.
检查每个字节是否有空终止符:
0xBF006665 & 0x000000FF 0x00000065 != 0,0xBF006665 & 0x0000FF00 0x00006600 != 0,0xBF006665 & 0x00FF0000 0x00000000 == 0 !!!
所以我们返回len 2; len是4,因为我们将它一次增加4,所以我们返回6,这确实是字符串的长度.