2

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

これらのビット演算の意味は何ですか?彼らの意図は何ですか?

4

2 に答える 2

7

基本的な考え方は、整列の制約を満たすことです。一度に 1 単語ずつコピーされる各「単語」は、「単語」境界に整列する必要があります。

一部の CPU には、これが基本的な制約としてあり、ロードとストアは「自然な」境界で発生する必要があります。古い ARM プロセッサでは、アドレスの下位ビットは実際には完全に無視されるため、奇数値アドレスからの 2 バイトのロードまたはストアは、次と同じ効果があります。

short w = *(short *)(addr & ~1);

例えば。他の一部の CPU では、アラインされていないロードまたはストアによってトラップが発生し (MIPS および SPARC など)、他の CPU ではトラップが発生しますが、パフォーマンスが低下します (x86)。

したがって、アドレス 0x12345 からアドレス 0x22345 に多数のバイト (たとえば、4096 バイト) をコピーしていて、「ワード サイズ」が 4 バイトであるとします。最初に 3 バイトをコピーすると、アドレスは 0x12348 と 0x22348 になります。この時点で、アラインメントの問題につまずくことなく、一度に 1 ワードずつ 1023 個の 4 バイト ワードをコピーできます。その後、4096 = 3 + (4 * 1023) + 1 であるため、コピーする残りの 1 バイトがあります。

これはすべて、「単語」をロードおよび保存する場合でも、バイトがすべて個別にアドレス指定されることを前提としています。この仮定は一部のマシンでは正しくありません。たとえば、古い Data General MV10000 CPU は「ワード アドレス」を使用して「ワード」をアドレス指定していました。これは基本的にバイト アドレスを 2 で割ったものです。(したがって、2 バイトにまたがる「ワード」をアドレス指定することは不可能です。ロケーション 0 のワードはバイト アドレス 0 と 1 を持ちますが、ワード アドレスは 0 です。ロケーション 1 のワードはバイト アドレス 2 と 3 を持ち、ロケーション 2 のワードはバイト アドレスを持ちます。アドレス 4 と 5 など)。このようなマシンでは、別のバージョンの bcopy.c を使用する必要がある場合があります。

@Alexが指摘したように、XORは2つのアドレスを実際に整列できることを確認しているだけです。0x12345 から 0x22345 にコピーしている場合は、そうです。ただし、0x12345 から 0x22344 にコピーする場合、2 つのアドレスは決して一致しません。

于 2012-06-28T04:32:16.293 に答える
6

ステップごとに実行してください:

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

srcこれらは、との少なくとも 1 つがdstの倍数でないかどうかをチェックしsizeof(long)ます。

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

これは、srcdstが異なる wrt sizeof(long)(IOW、 の「等しい」倍数ではないsizeof(long)) または ifの位置合わせされているかどうかをチェックしますlength < sizeof(long)-1

最後に、tアラインされていない場所の間のバイトとしてコピーする必要があるバイト数を受け取ります。すべて ( )、またはの倍数のアドレスに到達するのにlength十分 ( 未満) のいずれかで、残りは の単位でコピーできます。後者は速度の最適化です。sizeof(long)sizeof(long)long

すべてを理解するには、2 進法で表した整数は、ある 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)が目的です。

于 2012-06-28T04:08:02.163 に答える