memmove
とはどう違いmemcpy
ますか?普段どちらをどのように使用していますか?
9 に答える
を使用memcpy
すると、宛先はソースとまったくオーバーラップできません。それでmemmove
できます。これは、同じ仮定を行うことができないため、memmove
よりもわずかに遅い可能性があることを意味します。memcpy
たとえば、memcpy
アドレスを常に低いものから高いものにコピーする場合があります。宛先が送信元の後で重複している場合、これは一部のアドレスがコピーされる前に上書きされることを意味します。memmove
この場合、これを検出し、反対方向(高から低)にコピーします。ただし、これを確認して別の(おそらく効率の低い)アルゴリズムに切り替えるには時間がかかります。
memmove
重複するメモリを処理できますが、memcpy
できません。
検討
char[] str = "foo-bar";
memcpy(&str[3],&str[4],4); //might blow up
明らかに、ソースと宛先が重複しているため、「-bar」を「bar」で上書きしています。ソースと宛先がオーバーラップするかどうかを使用するのは未定義の動作なmemcpy
ので、この場合はが必要memmove
です。
memmove(&str[3],&str[4],4); //fine
一方 ( memmove
) は重複する宛先を処理し、もう一方 ( memcpy
) は処理しません。
ISO/IEC:9899 規格から簡単に説明されています。
7.21.2.1 memcpy 関数
[...]
2 memcpy 関数は、s2 が指すオブジェクトから s1 が指すオブジェクトに n 文字をコピーします。重複するオブジェクト間でコピーが行われる場合、動作は未定義です。
と
7.21.2.2 memmove 関数
[...]
2 memmove 関数は、s2 が指すオブジェクトから s1 が指すオブジェクトに n 文字をコピーします。コピーは、s2 が指すオブジェクトの n 文字が最初に、s1 および s2 が指すオブジェクトと重複しないn 文字の一時配列にコピーされ、次に一時配列の n 文字が次の場所にコピーされるかのように行われます。 s1 が指すオブジェクト。
質問に従って、私が通常使用するものは、必要な機能によって異なります。
プレーンテキストではオーバーラップは許可されmemcpy()
ませんが、whileは許可されます。s1
s2
memmove()
実装する明白な方法が 2 つありますmempcpy(void *dest, const void *src, size_t n)
(戻り値を無視します)。
for (char *p=src, *q=dest; n-->0; ++p, ++q) *q=*p;
char *p=src, *q=dest; while (n-->0) q[n]=p[n];
最初の実装では、コピーは低アドレスから高アドレスに進み、2 番目の実装では、高アドレスから低アドレスに進みます。コピーする範囲が重なっている場合 (たとえば、フレームバッファをスクロールする場合など)、一方の方向の操作のみが正しく、もう一方の方向は後で読み取られる場所を上書きします。
最も単純な実装では、 (プラットフォームに依存する方法で)memmove()
テストし、適切な方向を実行します。dest<src
memcpy()
もちろん、ユーザーコードはそれを行うことはできません。キャストして具体的なポインター型に変換した後でも、src
(dst
一般に) 同じオブジェクトを指していないため、比較できないためです。しかし、標準ライブラリは、未定義の動作を引き起こすことなく、そのような比較を実行するのに十分なプラットフォームの知識を持つことができます。
実際には、大規模な転送 (アラインメントが許す場合) および/または適切なデータ キャッシュの使用率から最大のパフォーマンスを得るために、実装はかなり複雑になる傾向があることに注意してください。上記のコードは、要点をできるだけ単純にするためのものです。
memmove は重複するソース リージョンと宛先リージョンを処理できますが、memcpy は処理できません。2 つのうち、memcpy ははるかに効率的です。したがって、可能であれば memcpy を使用することをお勧めします。
参照: https://www.youtube.com/watch?v=Yr1YnOVG-4g Jerry Cain 博士、(Stanford Intro Systems Lecture - 7) 時間: 36:00