web-dev-qa-db-ja.com

構造体に複数の値を一度に割り当てる方法は?

Struct Fooの初期化でこれを行うことができます。

Foo foo =  {bunch, of, things, initialized};

しかし、私はこれを行うことはできません:

Foo foo;
foo = {bunch, of, things, initialized};

したがって、2つの質問:

  1. 前者は初期化専用の特別なコンストラクターですか?
  2. 2番目の例に似た何かを行うにはどうすればよいですか?つまり、すでに初期化された後、1行のコードで構造体の変数の束を宣言できますか?私は多くの変数を持つ大きな構造体に対してこれをしなくて済むようにしています:

    Foo foo;
    
    foo.a = 1;
    foo.b = 2;
    foo.c = 3;
    //... ad infinitum
    
38
jim

1つ目は集約イニシャライザーです。このソリューションでは、これらのイニシャライザーとタグ付きイニシャライザーを確認できます。

タグ付き構造体初期化構文とは

これは特別な初期化構文であり、構造体の初期化後は同様のことはできません。あなたができることは、メンバー関数内で割り当てる一連の値をパラメータとして取るメンバー(または非メンバー)関数を提供することです-これは、構造が等しく初期化された後にこれを達成することができます簡潔(もちろん関数を初めて書いた後!)

これを試して:

Foo foo;
foo = (Foo){bunch, of, things, initialized};

これは、優れたコンパイラ(GCCなど)があれば機能します。 --std=gnu99でC99モードをオンにする必要があるかもしれませんが、わかりません。

30
David Grayson

C++ 11では、「tie」を使用して複数の割り当てを実行できます(Tupleヘッダーで宣言)

struct foo {
    int a, b, c;
} f;

std::tie(f.a, f.b, f.c) = std::make_Tuple(1, 2, 3);

右手式のサイズが固定されていて、一部の要素のみを取得する必要がある場合は、tieで無視プレースホルダーを使用できます

std::tie(std::ignore, f.b, std::ignore) = some_Tuple; // only f.b modified

構文std :: tie(f.a、f.b、f.c)のコードが煩雑だとわかる場合、その参照のタプルを返すメンバー関数を持つことができます

struct foo {
    int a, b, c;
    auto members() -> decltype(std::tie(a, b, c)) {
        return std::tie(a, b, c);
    }
} f;

f.members() = std::make_Tuple(1, 2, 3);

もちろん、このような値のシーケンスでは構造体を構築できないため、代入演算子のオーバーロードはオプションではないと想定しています。

f = foo(1, 2, 3);
9

効率をあまり気にしない場合は、二重に割り当てることができます:つまり、集計の初期化を使用して構造の新しいインスタンスを作成し、それをコピーします:

 struct Foo foo; 
 
 {
 struct Foo __tmp__ = {bunch、of、things、initialized}; 
 foo = __tmp __; 
} 

不要な一時変数が不要になったらすぐに破棄できるように、{}でラップされた部分を保持してください。

これは、たとえば、構造体(c ++の場合)または構造体の外で 'set'関数を作成し、構造体ポインター(Cの場合)を受け入れるほど効率的ではないことに注意してください。しかし、要素ごとの割り当てを書くことに代わる迅速で、できれば一時的な代替手段が必要な場合、これは可能性があります。

3
Codesmith

メモリフットプリント-興味深いi386の追加です。

面倒なことに、最適化およびmemcpyを使用すると、i386とGCCおよびC99を使用して最小のフットプリントが生成されるようです。ここでは-O3を使用しています。 stdlibはあらゆる種類の楽しいコンパイラ最適化を手元に持っているようで、この例はそれを利用しています(memcpyは実際にここでコンパイルされています)。

これを行うには:

Foo foo; //some global variable

void setStructVal (void)   {

    const Foo FOO_ASSIGN_VAL = {    //this goes into .rodata
            .bunch       = 1,
            .of          = 2,
            .things      = 3,
            .initialized = 4
    };

    memcpy((void*) &FOO_ASSIGN_VAL, (void*) foo, sizeof(Foo));

    return;
}

結果:

  • (.rodata)FOO_ASSIGN_VALは.rodataに保存されます
  • (.text)* movl FOO_ASSIGN_VALのシーケンス、%registers *が発生します
  • (.text)一連のmovl%registers、fooが発生します

例:

  • Say Fooは、uint8_t値の48フィールド構造体でした。メモリ内で整列されます。

  • [〜#〜] ideal [〜#〜])32ビットマシンでは、この[〜#〜] could [〜#〜]はfooのアドレス空間へのイミディエートの12 MOVL命令。私にとってこれは、サイズが12 * 10 == 120バイトの.textです。

  • [〜#〜] actual [〜#〜])ただし、AUTOによる回答を使用すると、.textに48個のMOVB命令が生成される可能性があります。私にとっては、これは48 * 7 == 336バイトの.textです!!

  • SMALLEST *)上記のmemcpyバージョンを使用します。アライメントが処理される場合、

    • FOO_ASSIGN_VALは.rodata(48バイト)に配置されます。
    • 12 MOVLから%register
    • 12個のMOVL out of%registersが.text(24 * 10)== 240bytesで使用されています。
    • 私にとっては、これは合計288バイトです。

少なくとも私のi386コードでは、

- Ideal:    120 bytes
- Direct:   336 bytes
- Smallest: 288 bytes

*ここで最小とは、「私が知っている最小のフットプリント」を意味します。また、上記の方法よりも高速に実行されます(24命令対48)。もちろん、IDEALバージョンは最速で最小ですが、まだわかりません。

-ジャスティン

*上記の '[〜#〜] ideal [〜#〜]'の実装を取得する方法を知っている人はいますか?それは私から地獄をいらいらさせます!!

2
J-Dizzle

効率を重視する場合は、構造と同じ長さのユニオンを、一度に割り当てることができるタイプで定義できます。

要素ごとに値を割り当てるには、ユニオンの構造体を使用し、データ全体を割り当てるには、他のタイプのユニオンを使用します。

typedef union
{
    struct
    {
      char a;
      char b;
    } Foo;
    unsigned int whole;
} MyUnion;

MyUnion _Union;
_Union.Foo.a = 0x23;    // assign by element
_Union.Foo.b = 0x45;    // assign by element
_Union.whole = 0x6789;  // assign at once

メモリの構成に注意してください(「a」はMSBですか、それとも「whole」のLSBですか?)。

0
Simon