Для чего нужны анонимные структуры и союзы в C11? - PullRequest
43 голосов
/ 20 января 2012

C11 добавляет, среди прочего, «Анонимные структуры и союзы».

Я ковырялся, но не мог найти четкого объяснения того, когда анонимные структуры и союзы будут полезны. Я спрашиваю, потому что я не совсем понимаю, что они есть. Я понимаю, что впоследствии они являются структурами или объединениями без имени, но я всегда (должен был?) Рассматривать это как ошибку, поэтому я могу представить себе использование только для именованных структур.

Ответы [ 6 ]

49 голосов
/ 20 января 2012

Анонимное объединение внутри структур очень полезно на практике. Предположим, что вы хотите реализовать различимый тип суммы (или теговое объединение ), агрегат с логическим значением и либо с плавающей точкой, либо 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.f и ch->u.s, которые менее читабельны и более многословны.

37 голосов
/ 14 октября 2014

Типичным и реальным использованием анонимных структур и союзов в мире является альтернативное представление данных.Например, при реализации типа 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;

Это полезно, если вы взаимодействуете с кодом, который ожидает трехмерный вектор в виде указателя на три двойных.Вместо того, чтобы делать f(&v.x), что уродливо, вы можете сделать f(v.raw), что прояснит ваши намерения.

7 голосов
/ 20 января 2012
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
0 голосов
/ 15 мая 2019

Я не уверен, почему 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
};
0 голосов
/ 20 января 2012
struct Lock;
int lock(Lock*);
...

struct Queue
{
    Lock;
    char buf[QBUFSIZE];
    char *rp;
    char *wp;
}

qputc(Queue* q, char c){
    lock(q);
    ...
}

update3 : ken c делает это некоторое время, например, для компиляции this this и это .

0 голосов
/ 20 января 2012

Хорошо, если вы объявляете переменные из этой структуры только один раз в своем коде, зачем ему имя?

struct {
 int a;
 struct {
  int b;
  int c;
 } d;
} e,f;

И теперь вы можете писать такие вещи, как e.a, f.d.b и т. Д.

(я добавил внутреннюю структуру, потому что я думаю, что это один из наиболее часто используемых анонимных структур)

...