23

最近まで、構造体フィールドのコピーがmemcpy(). クラスとオンラインの指示では、ある構造体の内容を別の構造体にコピーすることは、一般的に次のようになります。

struct block *b0 = malloc(sizeof(struct block));
struct block *b1 = malloc(sizeof(struct block));
/* populate fields in *b0 */
memcpy(b1, b0, sizeof *b1); /* copy contents of b0 into b1 */
/* free b0, b1 */

ただし、このタスクは、 を置き換える単純な割り当てによっても実行できますmemcpy()

*b1 = *b0; /* dereferenced struct assignment */

これが広く使用されていない正当な理由はありますか (少なくとも私の限られた経験では)? これら 2 つの方法 (代入と -は同等ですか?) または一般的memcpy()に使用する説得力のある理由はありますか?memcpy()

4

5 に答える 5

35

どちらの方法も同等であり、浅いコピーを実行します。これは、構造自体はコピーされますが、構造が参照するものはすべてコピーされないことを意味します。

なぜmemcpy人気があるのか​​はわかりません。古いバージョンのCは構造体の割り当てをサポートしていませんでした(1978年には一般的な拡張機能でしたが)。したがって、より移植性の高いコードを作成する方法として、おそらくmemcpyスタイルが残っていたのでしょうか。いずれにせよ、構造体の割り当てはPCコンパイラで広くサポートされており、使用するmemcpyとエラーが発生しやすくなります(サイズを間違えると、悪いことが起こる可能性があります)。したがって、可能な場合は構造体の割り当てを使用することをお勧めします。

ただし、機能する場合がありmemcpyます。例えば:

  • アラインされていないバッファとの間で構造をコピーする場合(たとえば、ディスクとの間で保存/ロードしたり、ネットワークで送受信したりする場合memcpy)、構造の割り当てにはソースと宛先の両方が適切にアラインされている必要があるため、を使用する必要があります。
  • 構造体の後に追加情報をパックする場合、おそらくゼロ要素配列を使用する場合は、を使用しmemcpy、この追加情報をサイズフィールドに含める必要があります。
  • 構造体の配列をコピーする場合は、構造体を個別にループしてコピーするよりも、単一の構造体をコピーする方が効率的な場合があります。memcpyそれからまた、そうではないかもしれません。言うのは難しいですが、memcpy実装はパフォーマンス特性が異なります。
  • 一部の組み込みコンパイラは、構造体の割り当てをサポートしていない場合があります。もちろん、問題のコンパイラがサポートしていない他のもっと重要なこともあるでしょう。

memcpyまた、Cと構造体の割り当ては通常同等ですが、C++memcpyと構造体の割り当ては同等ではないことにも注意してください。一般に、C ++memcpyは、構造体の割り当てがオーバーロードされて、ディープコピーや参照カウント管理などの追加の処理を実行できるため、構造体の使用を避けるのが最善です。

于 2012-11-08T07:05:02.667 に答える
6

これはあなたが探している正確な答えではありませんでした。

私が出会ったシナリオを説明しています。

を使用するmemcpy()と、宛先へのバイトごとのコピーが実行されます。したがって、ARMアーキテクチャでのデータアライメントについて心配する必要はありません。演算子を使用=していて、アドレスのいずれかが4バイトにアラインされていない場合、アラインメント障害が発生します。

Armサイトから:

書き込まれた最後のバイトを1バイト超えた宛先ロケーションへのポインタ。with perfect alignment of bytesこれにより、メモリブロックの文字列連結の書き込みプロセスを続行できます。

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0175k/Cihbbjge.html

于 2012-11-08T07:06:04.083 に答える
5

答えが実際に好まれる理由 を説明していないため、この古い質問を復活させています。memcpy

memcpyプログラマーが単にポインターではなくコンテンツをコピーしたいことが明確になるため、この方法が好まれます。

次の例では、2 つの割り当てによって 2 つの非常に異なるものが作成されます。

struct Type *s1,*s2;
*s1=*s2;
s1=s2;

誤って一方を他方の代わりに使用すると、悲惨な結果が生じる可能性があります。コンパイラは文句を言いません。初期化されていないポインターが使用されたときにプログラムがクラッシュしない限り、エラーは長い間気付かれず、奇妙な副作用を引き起こす可能性があります。

次のいずれかとして記述します。

memcpy(s1,s2,sizeof(*s1));
memcpy(s1,s2,sizeof(*s2));
memcpy(s1,s2,sizeof(struct Type));

意図がコンテンツをコピーすることであることを読者に知らせます (型の安全性と境界チェックを犠牲にして)。

一部のコンパイラ (gcc など) は、次のような場合に sizeof に関する警告を発行します。

memcpy(s1,s2,sizeof(s1));
于 2016-01-06T09:13:07.837 に答える
0

memcpy を好む人もいますが、それは彼らが学んだことであり、代入だけを実行できることを理解していなかったからです (昔は代入は許可されていませんでしたが、それはずっと昔のことです)。malloc () によって割り当てられたメモリは常に正しくアラインされるため、心配するアラインメントの問題はありません。また、コンパイラはこの割り当てを memcpy 呼び出しに自明に変換できるため、memcpy よりも遅くなったり、コードが多くなったりすることはありません。もちろん、時代遅れのコンパイラを使用する組み込みシステムもあります。

于 2014-03-31T14:18:29.503 に答える
-2

組み込みプラットフォームで作業している人は、構造体を直接代入する代わりに memcopy を使用することを好むでしょう。主に組み込みプラットフォームを扱う場合、一部のコンパイラは構造体の直接割り当てをサポートしていないため、memcopy を使用する必要があります。PC で作業している場合、どちらの場合も問題はありません。両方とも有効です。

于 2012-11-08T07:07:36.083 に答える