Какие анонимные структуры и союзы полезны для C11?
C11 добавляет, помимо прочего, "Анонимные структуры и союзы".
Я ткнул, но не смог найти ясного объяснения, когда полезны анонимные структуры и союзы. Я спрашиваю, потому что я не совсем понимаю, что это такое. Я получаю, что они являются структурами или объединениями без имени впоследствии, но я всегда (должен был?) Рассматривать это как ошибку, поэтому я могу только представить себе использование для названных структур.
Ответы
Ответ 1
Анонимные внутриутробные структуры очень полезны на практике. Подумайте, что вы хотите реализовать дискриминированный тип суммы (или tagged union), совокупность с логическим значением и либо 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.f
и ch->u.s
, который будет менее читабельным и более подробным.
Ответ 2
Типичным и реальным использованием анонимных структур и объединений является предоставление альтернативного представления данных. Например, при реализации трехмерного точечного типа:
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-вектор как указатель на три удвоения. Вместо f(&v.x)
, который является уродливым, вы можете сделать f(v.raw)
, что делает ваше намерение понятным.
Ответ 3
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
Ответ 4
Я не уверен, почему 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;
Это может быть полезно на практике, если кто-то собирает Linux с плагином компилятора для рандомизации порядка полей (эксплойт в стиле ASLR).
Ответ 5
Ну, если вы объявляете переменные из этой структуры только один раз в своем коде, зачем ему нужно имя?
struct {
int a;
struct {
int b;
int c;
} d;
} e,f;
Теперь вы можете писать такие вещи, как e.a
, f.d.b
и т.д.
(Я добавил внутреннюю структуру, потому что я считаю, что это одно из самых привычных анонимных структур)
Ответ 6
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.