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