Cで1つの構造体を別の構造体に割り当てます


146

次のように、構造体のインスタンスを別のインスタンスに割り当てることができますか?

struct Test t1;
struct Test t2;
t2 = t1;

私はそれが単純な構造で機能するのを見てきましたが、それは複雑な構造で機能しますか?
コンパイラーは、データ型をデータ型に応じてコピーする方法をどのように知っていintますか?つまり、と文字列を区別していますか?

回答:


151

構造が同じタイプであれば、はい。メモリコピーと考えてください。


72
深いコピーはなく、メモリをポイントしてもコピーされないことに注意してください。
GeorgSchölly、2010

3
ここでは並行性も問題です。
Tim Post

16
@Tim同時実行性は、整数や倍精度浮動小数点数などの組み込み型の割り当てよりも問題ではありません-割り当てもこれらのアトミック操作ではありません。

2
コピーが作成された場合、後でfree()を使用してメモリを解放できますか?
Betlista 2012年

5
@Betlista自動変数であるため、free()を使用してメモリを解放することはできません:en.wikipedia.org/wiki/Automatic_variable
joshdoe

138

はい、構造体では割り当てがサポートされています。ただし、問題があります。

struct S {
   char * p;
};

struct S s1, s2;
s1.p = malloc(100);
s2 = s1;

これで、両方の構造体のポインタは同じメモリブロックを指します-コンパイラは、指し示されたデータをコピーしません。現在、どの構造体インスタンスがデータを所有しているかを知ることは困難です。これが、C ++がユーザー定義可能な代入演算子の概念を発明した理由です-このケースを処理する特定のコードを書くことができます。


1
私はそれを読んで自分の答えの誤り/脱落に気づいたのでそれを上げました。
クリフォード

1
+1は、実際にはコピーが行われていないことに注意してください。
Tom Duckering、2010

14
なぜこれがスパムとして報告されたのですか?誰かがマウスをコントロールできなくなりましたか?
Georg Fritzsche、2010

@gfそして明らかにあまりにも不快です!

2
@rahmanisbackこのトピックについて、anonの答えは非常に明確です。「コンパイラは、ポイントされたデータをコピーしません」。struct自身のデータは明確にコピーされます。
トビアス

24

この例を最初に見てください:

簡単なCプログラムのCコードを以下に示します。

struct Foo {
    char a;
    int b;
    double c;
    } foo1,foo2;

void foo_assign(void)
{
    foo1 = foo2;
}
int main(/*char *argv[],int argc*/)
{
    foo_assign();
return 0;
}

foo_assign()の同等のASMコードは

00401050 <_foo_assign>:
  401050:   55                      push   %ebp
  401051:   89 e5                   mov    %esp,%ebp
  401053:   a1 20 20 40 00          mov    0x402020,%eax
  401058:   a3 30 20 40 00          mov    %eax,0x402030
  40105d:   a1 24 20 40 00          mov    0x402024,%eax
  401062:   a3 34 20 40 00          mov    %eax,0x402034
  401067:   a1 28 20 40 00          mov    0x402028,%eax
  40106c:   a3 38 20 40 00          mov    %eax,0x402038
  401071:   a1 2c 20 40 00          mov    0x40202c,%eax
  401076:   a3 3c 20 40 00          mov    %eax,0x40203c
  40107b:   5d                      pop    %ebp
  40107c:   c3                      ret    

アセンブリでは割り当てが「mov」命令に置き換えられるだけであることがわかるように、割り当て演算子は、あるメモリロケーションから別のメモリロケーションにデータを移動することを意味します。割り当ては、構造体の直接のメンバーに対してのみ実行され、構造体に複雑なデータ型がある場合はコピーに失敗します。ここでCOMPLEXは、リストを指すポインターの配列を持つことができないことを意味します。

構造体内の文字の配列自体は、ほとんどのコンパイラーでは機能しません。これは、代入がデータ型を複雑な型であると見なさずにコピーしようとするためです。


2
それが失敗する原因となるどの条件について詳しく説明できますか?それは常に私にとってはうまくいくようです
AlphaGoku

15

これは、あなたがそうするのと同じように、単純なコピーですmemcpy()(実際、一部のコンパイラは実際memcpy()にそのコードの呼び出しを生成します)。Cには「文字列」はなく、charの束へのポインタのみです。ソース構造にそのようなポインターが含まれている場合、chars自体ではなく、ポインターがコピーされます。


OK、コンパイラはこれをするために変換さそうmemcpy、ここを参照してください:godbolt.org/z/nPxqWcを -しかし、今、私は同じポインタを渡す場合ab、と*a = *bに変換されるmemcpyためので、未定義の動作であることmemcpy「メモリ領域ではない重複しなければなりません」(manページから引用)。それで、コンパイラは使用memcpyに誤りがありますか、それともそのような割り当てを書くのに間違っていますか?
ユーザーではない

6

実数部と虚数部を持つ複素数のような「複雑な」という意味ですか?これはありそうにないので、「複雑な」とはC言語に関して特定のものを意味しないので、例を挙げなければならないでしょう。

構造の直接メモリコピーを取得します。それが必要かどうかは、構造によって異なります。たとえば、構造にポインタが含まれている場合、両方のコピーが同じデータを指します。これは必要な場合とそうでない場合があります。それはあなたのプログラム設計にかかっています。

「スマート」コピー(または「ディープ」コピー)を実行するには、コピーを実行する関数を実装する必要があります。これは、構造自体にポインターと、ポインターも含む構造、およびおそらくそのような構造へのポインター(おそらく「複雑な」という意味)が含まれていて、維持するのが難しい場合、達成するのが非常に困難です。単純な解決策は、C ++を使用して、構造またはクラスごとにコピーコンストラクターと代入演算子を実装することです。その後、それぞれが独自のコピーセマンティクスを担当し、代入構文を使用できます。また、より簡単に維持できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.