如何理解bionic.c中bionic的这段代码片段?

时间:2012-06-28 03:22:52

标签: android c bionic

我在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);

这些按位运算的意思是什么?他们的意图是什么?

2 个答案:

答案 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)

检查srcdst中是否至少有一个不是sizeof(long)的倍数。

if ((t ^ (long)dst) & wmask || length < wsize)

这会检查srcdst是否以不同方式对齐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)的用途。