我正在从glibc读取“strlen”源代码,开发人员发现加速它的技巧是读取n个字节,其中n是长字的大小,而不是每次迭代读取1个字节。 / p>
我会假设一个长字有4个字节。
棘手的部分是函数读取的每个4字节“块”可以包含一个空字节,因此在每次迭代时,函数必须检查块中是否有空字节。他们这样做
if (((longword - lomagic) & ~longword & himagic) != 0) { /* null byte found */ }
其中longword
是数据块,himagic
和lowmagic
是神奇的定义为:
himagic = 0x80808080L;
lomagic = 0x01010101L;
以下是thoses值的评论
/* Bits 31, 24, 16, and 8 of this number are zero. Call these bits
the "holes." Note that there is a hole just to the left of
each byte, with an extra at the end:
bits: 01111110 11111110 11111110 11111111
bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
The 1-bits make sure that carries propagate to the next 0-bit.
The 0-bits provide holes for carries to fall into. */
找到空字节的这个技巧如何工作?
答案 0 :(得分:4)
来自着名的"Bit Twiddling Hacks" page作者Sean Eron Anderson,描述了你所指的glibc
实现中当前使用的内容(Anderson称算法为hasless(v, 1)
):
子表达式
(v - 0x01010101UL)
,计算为高位设置 任何字节,只要v中的相应字节为零或大于0x80
。子表达式~v & 0x80808080UL
求值为高位集 以字节为单位,其中v的字节没有设置其高位(所以 byte小于0x80
)。最后,通过ANDing这两个子表达式 结果是高位设置,其中v中的字节为零,因为 由于第一个中的值大于0x80
而设置的高位 子表达式被第二个掩盖。
glibc
来源中的评论似乎令人困惑,因为它不再适用于代码实际正在做的事情 - 它描述了什么是实现Anderson在描述hasless(v, 1)
算法之前描述的算法。