如何理解的仿生bcopy.c这个代码片断?(How to understand this code

2019-09-18 16:28发布

我读的中的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);

什么是这些位操作的是什么意思? 什么是他们的意图是什么?

Answer 1:

其基本思路是,以满足对齐约束:每一个“字”同时要复制一个字必须在一个“字”边界对齐。

一些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,这两个地址永远不会排队。



Answer 2:

只要做到这一步一步:

t = (long)src;
if ((t | (long)dst) & wmask)

这些检查是否至少一个srcdst不是的倍数sizeof(long)

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

这个检查srcdst排列不同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)是。



文章来源: How to understand this code snippet in the bcopy.c of bionic?
标签: android c bionic