简体   繁体   English

匿名结构和联合何时在 C11 中有用?

[英]When are anonymous structs and unions useful in C11?

C11 adds, among other things, 'Anonymous Structs and Unions'. C11 添加了“匿名结构和联合”等内容。

I poked around but could not find a clear explanation of when anonymous structs and unions would be useful.我四处寻找,但找不到关于匿名结构和联合何时有用的明确解释。 I ask because I don't completely understand what they are.我问是因为我不完全理解它们是什么。 I get that they are structs or unions without the name afterwards, but I have always (had to?) treat that as an error so I can only conceive a use for named structs.后来我知道它们是没有名称的结构或联合,但我一直(不得不?)将其视为错误,因此我只能设想使用命名结构。

Anonymous union inside structures are very useful in practice.结构内部的匿名联合在实践中非常有用。 Consider that you want to implement a discriminated sum type (or tagged union ), an aggregate with a boolean and either a float or a char* (ie a string), depending upon the boolean flag.考虑到您想要实现一个有区别的 sum 类型(或标记的 union ),一个带有布尔值和浮点数或char* (即字符串)的聚合,具体取决于布尔标志。 With C11 you should be able to code使用 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);
}

With C99, you'll have to name the union, and code ch->uf and ch->us which is less readable and more verbose.使用 C99,您必须为联合命名,并编码ch->ufch->us ,这会降低可读性且更冗长。

Another way to implement some tagged union type is to use casts.实现某些标记联合类型的另一种方法是使用强制转换。 The Ocaml runtime gives a lot of examples. Ocaml 运行时提供了很多示例。

The SBCL implementation of Common Lisp does use some union to implement tagged union types. Common Lisp 的SBCL实现确实使用一些union来实现标记联合类型。 And GNU make also uses them. GNU make也使用它们。

A typical and real world use of anonymous structs and unions are to provide an alternative view to data.匿名结构和联合的典型和现实用途是提供另一种数据视图。 For example when implementing a 3D point type:例如在实现 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;

This is useful if you interface to code that expects a 3D vector as a pointer to three doubles.如果您与需要 3D 向量作为指向三个双精度值的指针的代码交互,这将非常有用。 Instead of doing f(&v.x) which is ugly, you can do f(v.raw) which makes your intent clear.而不是做丑陋的f(&v.x) ,你可以做f(v.raw)这让你的意图变得清晰。

struct bla {
    struct { int a; int b; };
    int c;
};

the type struct bla has a member of a C11 anonymous structure type.类型struct bla有一个 C11 匿名结构类型的成员。

struct { int a; int b; } struct { int a; int b; } has no tag and the object has no name: it is an anonymous structure type. struct { int a; int b; }没有标签,对象也没有名字:它是一个匿名结构类型。

You can access the members of the anonymous structure this way:您可以通过以下方式访问匿名结构的成员:

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

Another useful implementation is when you are dealing with rgba colors, since you might want access each color on its own or as a single int.另一个有用的实现是当您处理 rgba 颜色时,因为您可能希望单独访问每种颜色或作为单个 int 访问。

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

Now you can access the individual rgba values or the entire value, with its highest byte being rie:现在您可以访问单个 rgba 值或整个值,其最高字节为 rie:

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

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

    return 0;
}

Prints 11AACCFF打印 11AACCFF

I'm not sure why C11 allows anonymous structures inside structures.我不确定为什么 C11 允许在结构中使用匿名结构。 But Linux uses it with a certain language extension :但是 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;

I'm not sure if that example strictly necessary, except to make the intent clear.我不确定这个例子是否绝对必要,除了明确意图。

EDIT: I found another similar pattern which is more clear-cut.编辑:我发现了另一个更清晰的类似模式。 The anonymous struct feature is used with this attribute:匿名结构功能与此属性一起使用:

#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

Ie a language extension / compiler plugin to randomize field order (ASLR-style exploit "hardening"):即随机化字段顺序的语言扩展/编译器插件(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
};

Well, if you declare variables from that struct only once in your code, why does it need a name?好吧,如果您在代码中只从该结构声明一次变量,为什么它需要一个名称?

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

And you can now write things like ea , fdb ,etc.您现在可以编写eafdb等内容。

(I added the inner struct, because I think that this is one of the most usages of anonymous structs) (我添加了内部结构体,因为我认为这是匿名结构体的最多用法之一)

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 is doing that for a while - for example, for compiling this this and this . UPDATE3: 肯Ç是这样做了一段时间-例如,编译这个 这个这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM