我读的中的memcpy实现http://androidxref.com/4.0.4/xref/bionic/libc/string/bcopy.c找到下面的代码是很难理解的,任何人可以解释一下吗?
36 /*
37 * sizeof(word) MUST BE A POWER OF TWO
38 * SO THAT wmask BELOW IS ALL ONES
39 */
40 typedef long word; /* "word" used for optimal copy speed */
41
42 #define wsize sizeof(word)
43 #define wmask (wsize - 1)
44
...
/*
78 * Copy forward.
79 */
80 t = (long)src; /* only need low bits */
81 if ((t | (long)dst) & wmask) {
82 /*
83 * Try to align operands. This cannot be done
84 * unless the low bits match.
85 */
86 if ((t ^ (long)dst) & wmask || length < wsize)
87 t = length;
88 else
89 t = wsize - (t & wmask);
什么是这些位操作的是什么意思? 什么是他们的意图是什么?
其基本思路是,以满足对齐约束:每一个“字”同时要复制一个字必须在一个“字”边界对齐。
一些CPU有这个作为基本约束,即加载和存储必须在“自然”的边界发生。 在较旧的ARM处理器中的地址的低位被完全忽略,从而使从奇数值地址的负载或两个字节存储有同样的效果为:
short w = *(short *)(addr & ~1);
例如。 在一些其他CPU未对齐加载或存储的结果陷阱(MIPS和SPARC为例),还有人会做它,但性能上的损失(86)。
因此,假设你是从地址0x12345复制大量的字节数(比如说,他们的4096),以解决0x22345,并认为“字大小”为4个字节。 如果我们先复制三个字节,该地址现在将0x12348和0x22348。 在这一点上,我们可以只复制1023 4字节的话,每次一个字,没有绊倒在任何对齐问题。 之后,我们将有一个剩余字节复制,因为4096 = 3 +(4 * 1023)+ 1。
这一切都使得假设字节都单独寻址,装入和存储的“字”时也是如此。 这个假设是在一些机器上虚假的:例如,旧的通用数据MV10000 CPU将解决“字”用“字地址”,其本质上是字节除以二的地址。 (这是因此不可能以解决一个“字”跨越两个字节:在位置0的字具有字节地址0和1,但字地址0;在位置1中的字具有字节地址2和3;在位置2上的字具有字节地址4和5;等等),在这样的机器上,你可能需要使用不同版本的bcopy.c的。
作为@Alex指出,异或只是确保它实际上是可以对准两个地址。 如果你从0x12345复制到0x22345,它是; 但是,如果您复制0x12345到0x22344,这两个地址永远不会排队。
只要做到这一步一步:
t = (long)src;
if ((t | (long)dst) & wmask)
这些检查是否至少一个src
和dst
不是的倍数sizeof(long)
。
if ((t ^ (long)dst) & wmask || length < wsize)
这个检查src
和dst
排列不同WRT sizeof(long)
(IOW,不是“相等”的倍数sizeof(long)
),或者如果length < sizeof(long)-1
。
在最后你在收到t
多少字节必须被复制为未对齐的位置之间的字节,要么全部( length
),或刚好够(小于sizeof(long)
),以达到该多个的地址sizeof(long)
来自哪里其余的可以在单位被复制long
。 而后者则是速度优化。
要看到所有你要知道,一个整数,以二进制表示的时候,是2的一定功率的倍数时的2次幂低于其至少显著位全是零。
例子:
100 2(4×10)是100 2(4×10)的倍数
1100 2(12 10)的100 2(4×10)的倍数
10000 2(16 10)的100 2(4×10)的倍数
0 2(0 10)是100 2(4×10)的倍数
11 2(3 10)不是100 2(4×10)的倍数
1101 2(13 10)不是100 2(4×10)的倍数
这就是& (sizeof(long)-1)
的用途。
你还需要知道的值XORed
与自己给出0,当你XOR
不同的值,结果为非零。 所以,你可以使用XOR
进行比较。 而这正是(t ^ (long)dst)
是。