什么是在C11中有用的匿名结构和联合?

时间:2012-01-19 20:20:27

标签: c struct c11

除其他事项外,C11还增加了“匿名结构和联盟”。

我四处寻找,但无法找到匿名结构和联盟何时有用的明确解释。我问,因为我不完全明白它们是什么。我得知它们之后是没有名字的结构或联合,但我总是(必须?)将其视为一个错误,所以我只能设想使用命名结构。

7 个答案:

答案 0 :(得分:48)

内部结构中的匿名联合在实践中非常有用。考虑您要实现一个有区别的和类型(或tagged union),一个带有布尔值的聚合以及一个浮点数或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不太可读且更详细。

答案 1 :(得分:36)

匿名结构和联合的典型和现实世界的使用是提供数据的替代视图。例如,在实现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矢量作为指向三个双精度的指针,那么这非常有用。您可以f(&v.x)执行f(v.raw)而不是执行丑陋的{{1}},这样可以明确您的意图。

答案 2 :(得分:6)

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

答案 3 :(得分:0)

我不确定C11为什么在结构内部允许匿名结构。但是Linux将其与a certain language extension一起使用:

/**
 * 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;

除了明确意图之外,我不确定该示例是否绝对必要。

编辑:我发现了另一个类似的模式,它更清晰。匿名struct功能与此属性一起使用:

#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
};

答案 4 :(得分:0)

另一种有用的实现是在处理rgba颜色时,因为您可能想单独或作为单个int访问每种颜色。

typedef struct {
    union{
        struct {uint8_t a, b, g, r;};
        uint32_t val;
    };
}Color;

现在,您可以访问单个rgba值或整个值,其最高字节为r。即:

int main(void)
{
    Color x;
    x.r = 0x11;
    x.g = 0xAA;
    x.b = 0xCC;
    x.a = 0xFF;

    printf("%X\n", x.val);

    return 0;
}

打印11AACCFF

答案 5 :(得分:-1)

好吧,如果你在代码中只声明一次该结构中的变量,为什么它需要一个名字呢?

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

您现在可以编写e.af.d.b等内容。

(我添加了内部结构,因为我认为这是匿名结构中最常用的一种)

答案 6 :(得分:-3)

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 thisthis