web-dev-qa-db-ja.com

C11で便利な匿名の構造体と共用体は何ですか?

C11は、特に「匿名の構造と連合」を追加しています。

私はいろいろと調べましたが、匿名の構造体と共用体がいつ役立つかについての明確な説明を見つけることができませんでした。私は彼らが何であるかを完全に理解していないので尋ねます。後に名前のない構造体または共用体であることがわかりますが、名前付き構造体の使用しか考えられないため、それを常にエラーとして扱う必要がありました。

44
griotspeak

構造内の匿名結合は、実際には非常に便利です。差別化された合計タイプ(または タグ付きユニオン )、ブール値に応じてブール値とfloatまたはchar*(つまり文字列)の集合体を実装するとします。 。 C11を使用すると、コーディングできるはずです

typedef struct {
    bool is_float;
    union {
       float f;
       char* s;
    };
} mychoice_t;

double as_float(mychoice_t* ch) 
{ 
   if (ch->is_float) return ch->f;
   else return atof(ch->s);
}

C99では、ユニオンに名前を付け、ch->u.fch->u.sをコーディングする必要がありますが、これらは読みにくく冗長です。

50

匿名の構造体および共用体の一般的かつ現実的な使用法は、データの代替ビューを提供することです。たとえば、3Dポイントタイプを実装する場合:

_typedef struct {
    union{
        struct{
            double x; 
            double y;
            double z;
        };
        double raw[3];
    };
}vec3d_t;

vec3d_t v;
v.x = 4.0;
v.raw[1] = 3.0; // Equivalent to v.y = 3.0
v.z = 2.0;
_

これは、3Dベクトルを3つのdoubleへのポインターとして予期するコードにインターフェースする場合に役立ちます。いf(&v.x)を実行する代わりに、f(v.raw)を実行して意図を明確にすることができます。

40
Emily L.
struct bla {
    struct { int a; int b; };
    int c;
};

タイプ struct blaには、C11匿名構造型のメンバーがあります。

struct { int a; int b; }にはタグがなく、オブジェクトには名前がありません。これは匿名構造型です。

この方法で、匿名構造のメンバーにアクセスできます。

struct bla myobject;
myobject.a = 1;  // a is a member of the anonymous structure inside struct bla   
myobject.b = 2;  // same for b
myobject.c = 3;  // c is a member of the structure struct bla
7
ouah

C11が構造内の匿名構造を許可する理由はわかりません。しかし、Linuxは 特定の言語拡張 でそれを使用します:

/**
 * struct blk_mq_ctx - State for a software queue facing the submitting CPUs
 */
struct blk_mq_ctx {
    struct {
        spinlock_t      lock;
        struct list_head    rq_lists[HCTX_MAX_TYPES];
    } ____cacheline_aligned_in_smp;

    /* ... other fields without explicit alignment annotations ... */

} ____cacheline_aligned_in_smp;

意図を明確にすることを除いて、その例が厳密に必要かどうかはわかりません。

編集:より明確な別の同様のパターンを見つけました。匿名構造体機能は、次の属性で使用されます。

#if defined(RANDSTRUCT_PLUGIN) && !defined(__CHECKER__)
#define __randomize_layout __attribute__((randomize_layout))
#define __no_randomize_layout __attribute__((no_randomize_layout))
/* This anon struct can add padding, so only enable it under randstruct. */
#define randomized_struct_fields_start  struct {
#define randomized_struct_fields_end    } __randomize_layout;
#endif

つまりフィールドの順序をランダム化するための言語拡張/コンパイラプラグイン(ASLRスタイルのエクスプロイト「強化」):

struct kiocb {
    struct file     *ki_filp;

    /* The 'ki_filp' pointer is shared in a union for aio */
    randomized_struct_fields_start

    loff_t          ki_pos;
    void (*ki_complete)(struct kiocb *iocb, long ret, long ret2);
    void            *private;
    int         ki_flags;
    u16         ki_hint;
    u16         ki_ioprio; /* See linux/ioprio.h */
    unsigned int        ki_cookie; /* for ->iopoll */

    randomized_struct_fields_end
};
1
sourcejedi