web-dev-qa-db-ja.com

名前のない構造体でネストされたc unionの使用方法

私はいわゆるHotspotオープンソースプロジェクトに取り組んでおり、実装を見ると、次のような構造の厄介な入れ子になったユニオンが見つかりました。

typedef struct RC_model_t_st
{
    union
    {
        struct block_model_t_st *block;
        struct grid_model_t_st *grid;
    };
    /* block model or grid model    */
    int type;
    thermal_config_t *config;
}RC_model_t;

私がC/C++で知っている限り、ユニオンはアクセス不可能です。それでは、そのように宣言された労働組合をどのようにしてどのように利用できるのでしょうか。

ありがとう!

15
zwx

これはanonymous union。 C++では、[class.union]の段落5のとおりです。

名前検索の目的で、匿名組合の定義後、匿名組合のメンバーは、匿名組合が宣言されているスコープで定義されていると見なされます。

つまり、RC_model_t_stのメンバーであるかのようにメンバーにアクセスできます。

26
Angew

確信が持てず、試みもしなかった場合:

組合自体はアクセスできませんが、メンバーはアクセスできます。

したがって、obj.blockおよびobj.gridを参照できるはずです。

8
Atmocreations

このコード( https://Gist.github.com/klange/404296 )は、構造体内の匿名ユニオンにアクセスする方法を示しています。ネストされた共用体のメンバーには、それらが構造体のメンバーであるかのようにアクセスするだけです。

typedef struct {
    union {
        char * company;
        char * school;
        char * project;
    };
    union {
        char * location;
        char * url;
    };
    union {
        char * title;
        char * program;
    };

    time_t started;
    time_t left;

    char * description[];
} thing_t;

typedef thing_t job_t;

job_t Yelp = {
    .company  = "Yelp, Inc.",
    .location = "San Francisco, CA",
    .title    = "Software Engineer, i18n",
    .started  = 1339977600,
    .left     = CURRENT,
    .description = {
        "Developed several internal tools and libraries",
        "Provided critical input and design work for Yelp's launch in Japan",
        NULL
    }
};
4
Phani

匿名の共用体と構造体に関する標準を引用してAngewによって提供された回答について詳しく説明するために、Cソースコードのサンプルに、structunionstructおよびunionコンポーネントで構成されています。

Angewが引用した標準は次のとおりです。

名前検索の目的で、匿名共用体の定義後、匿名共用体のメンバーは、匿名共用体が宣言されているスコープで定義されていると見なされます。

名前付きの匿名の構造体と共用体で構成されるstructのソースコードは、次のようになります。これはVisual Studio 2005を使用しており、#pragma (pack, 1)を使用してすべてをchar境界に配置し、メモリホールがないようにします。また、出力を読みやすくコーディングしやすくするために定義された単純なCプリプロセッサマクロもあります。

typedef unsigned char UCHAR;

// use of Microsoft Visual Studio pragma to force char alignment for the struct.
#pragma pack(Push, 1)
const struct {
    union {
        const UCHAR myArray[];  // this array shares memory with struct following
        struct {
            const UCHAR iOne;
            const UCHAR iTwo;
            const UCHAR iThree;
        };  // anonymous struct accessed by specifying Things.
    };      // anonymous union accessed by specifying Things.
//  const UCHAR myArray[];   // will cause error - "error C2020: 'myArray' : 'struct' member redefinition"
    union {
        const UCHAR myArray[];  // this array shares memory with struct following
        struct {
            const UCHAR iOne;
            const UCHAR iTwo;
            const UCHAR iThree;
        } s;    // named struct accessed by specifying Things.u.s
    } u;        // named union accessed by specifying Things.u
} Things = {1, 2, 4, 8, 9, 10, 22, 23, 24, 25};
#pragma pack(pop)

// a little helper macro to make the output easier to code.
#define PRINTF_VAL(x) printf ("%s %d \n", #x, x)

int itSelf (UCHAR iMask)
{
    int iMatch = -1;

    int jj = 0;
    jj = Things.myArray[0]; PRINTF_VAL(Things.myArray[0]);
    jj = Things.myArray[1]; PRINTF_VAL(Things.myArray[1]);
    jj = Things.myArray[2]; PRINTF_VAL(Things.myArray[2]);
    jj = Things.myArray[3]; PRINTF_VAL(Things.myArray[3]);
    jj = Things.myArray[4]; PRINTF_VAL(Things.myArray[4]);
    jj = Things.iOne; PRINTF_VAL(Things.iOne);
    jj = Things.iTwo; PRINTF_VAL(Things.iTwo);
    jj = Things.iThree; PRINTF_VAL(Things.iThree);

    jj = Things.u.myArray[0]; PRINTF_VAL(Things.u.myArray[0]);
    jj = Things.u.myArray[1]; PRINTF_VAL(Things.u.myArray[1]);
    jj = Things.u.myArray[2]; PRINTF_VAL(Things.u.myArray[2]);
    jj = Things.u.myArray[3]; PRINTF_VAL(Things.u.myArray[3]);
    jj = Things.u.myArray[4]; PRINTF_VAL(Things.u.myArray[4]);
    jj = Things.u.s.iOne; PRINTF_VAL(Things.u.s.iOne);
    jj = Things.u.s.iTwo; PRINTF_VAL(Things.u.s.iTwo);
    jj = Things.u.s.iThree; PRINTF_VAL(Things.u.s.iThree);

    return iMatch + 1;
}

この関数によって生成される出力は次のようになります。

Things.myArray[0] 1
Things.myArray[1] 2
Things.myArray[2] 4
Things.myArray[3] 8
Things.myArray[4] 9
Things.iOne 1
Things.iTwo 2
Things.iThree 4
Things.u.myArray[0] 8
Things.u.myArray[1] 9
Things.u.myArray[2] 10
Things.u.myArray[3] 22
Things.u.myArray[4] 23
Things.u.s.iOne 8
Things.u.s.iTwo 9
Things.u.s.iThree 10

出力は、共用体の使用によって引き起こされたメインstructThingsのさまざまなコンポーネント間のオーバーラップを示しています。匿名のstructおよびunionのコンポーネントが、名前付きのstructおよびunionのコンポーネントに対してどのように参照されているかも確認できます。

また、おもしろいことに、const UCHAR myArray[];を含む匿名のunionの後にconst UCHAR myArray[];の配列定義を追加して、何が起こるかを確認しました。コンパイラはerror C2020: 'myArray' : 'struct' member redefinitionのエラーを報告しました。追加は、上記のstructThings定義でコメント化されています。ただし、const UCHAR myArray[];の2番目の使用は名前付きunionであるので、共用体の名前を指定して2番目の使用にアクセスできるため、コンパイルは機能します。

3

匿名の共用体で宣言された名前は、非メンバー変数と同様に直接使用されます。これを行う正当な理由は、メモリを節約することです。

#include <iostream>

int main(int argc, char **argv) {
   union {
      double first;
      double second;
   };

   first = 10.001;
   second = 3.141592;
   std::cout << first << " " << second << std::endl;

   first = 10.002;
   std::cout << first << " " << second << std::endl;
}
2
sciarp