2012-11-08 5 views
18

最近まで、memcpy()で完了した構造体フィールドのコピーしか見ていませんでした。クラスとオンラインの指示では、別のものに1つの構造体の内容をコピーすることは、一般memcpy()の代りにCの構造体をコピーする

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()を使用する理由がありますか?

+3

を?? – Jeyaram

+7

Cでは、2つのメソッドは同等であり、どちらもディープコピーを行いません。 –

+2

'memcpy(b1、b0、sizeof(struct block));'は非常にスタイルが悪く、エラーを起こしやすいです。代入や 'memcpy(b1、b0、sizeof * b1);' –

答えて

27

どちらの方法も同等で、シャローコピーを実行します。つまり、構造体自体はコピーされますが、構造体が参照するものはすべてコピーされません。

理由はmemcpyが一般的ですが、わかりません。古いバージョンのCでは構造体の代入(although it was a common extension as early as 1978)がサポートされていなかったので、もっと移植性の高いコードを作る方法としてmemcpyスタイルが詰まっているのでしょうか?どのような場合でも、構造体の割り当てはPCコンパイラで広くサポートされていますが、memcpyを使用するとエラーが発生しやすくなります(サイズが間違っていると、Bad Thingsが起きる可能性が高い)ので、可能であれば構造体割り当てを使用することをお勧めします。

memcpyしか動作しない場合があります。たとえば、次のように

  • あなたが整列していないバッファにまたはから構造をコピーする場合 - 例えば、ディスクから/に/負荷を保存したり、ネットワーク上で受信/送信するために - あなたは、構造体の割り当てとして、memcpyを使用する必要があります送信元と送信先の両方を適切に調整する必要があります。
  • using a zero-element arrayなどの構造体の後に追加情報を入力する場合は、memcpyを使用し、この追加情報をサイズフィールドに入力する必要があります。
  • 構造体の配列をコピーする場合は、構造体を個別にループしたりコピーしたりするのではなく、memcpyを実行する方が効率的です。それではまた、そうではないかもしれません。つまり、memcpyの実装では、パフォーマンスの特性が異なります。
  • 埋め込みコンパイラの中には、構造体の割り当てをサポートしていないものがあります。もちろん、コンパイラがサポートしていない他の重要なこともあります。 C memcpyと構造の割り当てにCで、通常は同等であるが

も注意++ memcpyと構造の割り当ては、ない同等であること。一般的にC++では構造体の割り当てが深刻なコピーや参照カウントの管理などの追加作業を行うことができますが、しばしばオーバーロードされるので構造体を避けることが最善です。

+0

クール、ありがとう。深い/浅いコピーの混乱については申し訳ありません。私は、浅いコピーが '* b1 = * b0'の代わりに' b1 = b0'のようなポインタ割り当てのような印象を受けました。 – olliezhu

6

これは正確な答えではありませんでした。

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

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

に書き込まれた最後のバイトを超えた1バイトである宛先の場所へのポインタ。これにより、メモリブロックの文字列連結のための書き込みプロセスwith perfect alignment of bytesの継続が可能になります。

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

+2

コンパイラは、すべてが適切に整列されている必要はありませんか? – alk

+2

@alkを使用すると、コンパイラはすべてが適切に整列されているとみなします。これにより、多くのプラットフォームでパフォーマンスが大幅に向上します。あなたの構造体にメモリを割り当てるためにmallocを使うだけならば、それが整列していることを確認するでしょうが、ファイルやネットワークからポインタの算術演算や構造体の読み込みを開始すると、もはやそうではなくなってコンパイラの前提が破られ、動作。ほとんどのx86オペレーションでは、わずかなパフォーマンスの低下を伴い、非境界整列のアクセスが透過的に処理されるため、x86ではこれが表示されないことに注意してください。 – bdonlan

+0

@bdonlan十分に公正なI/Oバッファーの間での読み書きの問題があります。コンパイラが正しいコードを生成するために(コンパイル時に)必要なことを知っている必要があるので、なぜか(適切に型付けされた)ポインタ算術を使用して問題が生じるのはなぜですか。 – alk

-2

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

0

memcpyが好きな人は、それは彼らが学んだことであり、任務を遂行できると思ったことがないからです(古代では、割り当ては許可されていませんでしたが、それはずっと前です)。 malloc()によって割り当てられたメモリは常に正しく整列しているので、心配する整列の問題はありません。そして、コンパイラはこの割り当てをmemcpy呼び出しに簡単に変換できるので、memcpyより遅くてもコードでも決してありません。もちろん、古くなったコンパイラの組み込みシステムもあります。

3

答えが説明されないので、私はこの古い質問を復活させています。なぜmemcpyが実際に好ましいですか。

memcpyプログラマが単純にポインタではなく内容をコピーしたいことが明らかになるため、これが好ましい。

次の例では、2つの割り当ては、2つの非常に異なるものを作る:

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

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

の一つとして、それを書く:

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

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

いくつかのコンパイラ(例えばGCC)彼らは何か発生した場合でも、はsizeofについての警告を発行します。あなたは* B1 = * B0を意味

memcpy(s1,s2,sizeof(s1)); 
関連する問題