web-dev-qa-db-ja.com

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

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

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

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

133
shreyasva

構造が同じタイプの場合ははい。メモリコピーと考えてください。

137
fabrizioM

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

struct S {
   char * p;
};

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

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

127
anon

この例をまず見てください:

単純な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    

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

構造内の文字の配列自体は、ほとんどのコンパイラでは機能しません。これは、割り当てがデータ型を複雑な型と見なすことなくコピーを試みるだけだからです。

23
Arun Kaushal

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

15
Thomas Pornin

実数部と虚数部を持つ複素数のような「複雑な」という意味ですか?これはありそうにないので、「複雑」とはC言語の観点から具体的なものを意味しないので、例を挙げる必要があります。

構造の直接メモリコピーを取得します。それがあなたが望むものであるかどうかは、構造に依存します。たとえば、構造にポインターが含まれる場合、両方のコピーは同じデータを指します。これはあなたが望むものかもしれませんし、そうでないかもしれません。それはあなたのプログラムの設計次第です。

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

6
Clifford