我在http://androidxref.com/4.0.4/xref/bionic/libc/string/bcopy.c中阅读了memcpy实现 发现以下代码很难理解,有人可以解释一下吗?
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);
这些按位运算的意思是什么?他们的意图是什么?
答案 0 :(得分:7)
基本思想是满足对齐约束:每个&#34; word&#34;要一次复制一个单词,必须在&#34; word&#34;边界。
有些CPU将此作为基本约束,加载和存储必须在&#34;自然&#34;边界。在较旧的ARM处理器上,地址的低位实际上完全被忽略,因此从奇数值地址加载或存储两个字节具有与以下相同的效果:
short w = *(short *)(addr & ~1);
例如。在其他一些CPU上,未对齐的加载或存储会导致陷阱(例如MIPS和SPARC),还有一些只会这样做,但会带来性能损失(x86)。
因此,假设您正在将大量字节(例如,4096个)从地址0x12345复制到地址0x22345,并且&#34;字大小&#34;是4个字节。如果我们首先复制三个字节,地址现在将是0x12348和0x22348。此时,我们只能复制1023个4字节字,一次一个字,而不会因任何对齐问题而跳闸。之后,我们将剩下一个要复制的字节,因为4096 = 3 +(4 * 1023)+ 1.
这一切都假设字节都是单独处理的,即使在加载和存储&#34;单词&#34;时也是如此。在某些机器上,这种假设是错误的:例如,旧的Data General MV10000 CPU将解决&#34;单词&#34;使用&#34;字地址&#34;,它们本质上是字节地址除以2。 (因此不可能解决跨越两个字节的&#34;字&#34;位置0的字具有字节地址0和1但字地址0;位置1的字具有字节地址2和3;位置2的字具有字节地址4和5;依此类推。)在这样的机器上,您可能需要使用不同版本的bcopy.c。
正如@Alex所说,XOR只是确保实际上可以对齐这两个地址。如果你要从0x12345复制到0x22345,那就是;但如果您从0x12345复制到0x22344,这两个地址将永远不会对齐。
答案 1 :(得分:6)
一步一步地做:
t = (long)src;
if ((t | (long)dst) & wmask)
检查src
和dst
中是否至少有一个不是sizeof(long)
的倍数。
if ((t ^ (long)dst) & wmask || length < wsize)
这会检查src
和dst
是否以不同方式对齐w.r.t. 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)
的用途。