64

C11 adds, among other things, 'Anonymous Structs and Unions'.

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.

Community
  • 1
  • 1
griotspeak
  • 13,022
  • 13
  • 43
  • 54

6 Answers6

75

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* (i.e. a string), depending upon the boolean flag. With C11 you should be able to code

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->u.f and ch->u.s which is less readable and more verbose.

Another way to implement some tagged union type is to use casts. The Ocaml runtime gives a lot of examples.

The SBCL implementation of Common Lisp does use some union to implement tagged union types. And GNU make also uses them.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
64

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:

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. Instead of doing f(&v.x) which is ugly, you can do f(v.raw) which makes your intent clear.

Emily L.
  • 5,673
  • 2
  • 40
  • 60
  • This seems like it's venturing heavily into UB territory. Is there something in the standard that mandates that this will work? – Nic Oct 26 '16 at 16:55
  • 1
    @QPaysTaxes Why would it be UB? C++14 9.5.1 [class.union]: `Each non-static data member is allocated as if it were the sole member of a struct.` In other words `&v.raw[0] == &v.x` and as long as the inner struct is tightly packed, then `&v.raw[1] == &v.y` too. – Emily L. Oct 27 '16 at 08:14
  • I thought it might be because I don't know the language all that well. Thanks for the citation! – Nic Oct 27 '16 at 12:37
  • @EmilyL.: C89 never tried to define all forms of aliasing that quality implementations should support (since that should depend upon a compiler's platform and intended use case) and consequently failed to ensure behavior is defined even in many cases where it obviously should be (since quality implementations should support such cases whether or not the Standard compels it). Since array accesses are done through pointer decomposition and arithmetic, deliberately-obtuse compilers could apply creative "optimizations" with the fact that a struct is being accessed using a pointer which... – supercat Feb 10 '17 at 23:58
  • 2
    ...may be of a member type, but was not formed by taking the address of the member accessed thereby. Given that compilers are evolving in the direction of greater aggressiveness rather than greater sanity, and are willing to use extremely strained interpretations of the Standard to justify their behavior, I wouldn't trust compilers to usefully process code like the above without `-fno-strict-aliasing`. – supercat Feb 11 '17 at 00:00
  • @supercat nobody mentioned C89. I quoted C++14 which is well specified. – Emily L. Feb 12 '17 at 15:53
  • @EmilyL.: I should have added: C89 didn't specify such things, and since the world survived for ten years subsequent standards haven't seen the need to so either, even though the reason the world didn't end was that compilers weren't as aggressive as the Standard allowed. While I haven't tested the exact code above in godbolt, an interpretation of the Standard that would justify gcc's behavior in some other situations would probably let a compiler wreak havoc with the above code as well – supercat Feb 12 '17 at 22:30
  • @EmilyL. supercat isn't wrong; your quote is irrelevant. It's what happens if the inner struct *isn't* tightly packed that raises eyebrows, and C provides no real mechanism to ensure that it is appropriately packed, short of messing about with `offsetof` and `static_assert`. – Alex Celeste Mar 23 '17 at 15:39
  • @Leushenko `static_assert(sizeof(vec3d_t)==3*sizeof(double))`. Find me one compiler and platform with any setting where this will be false. – Emily L. Mar 24 '17 at 23:04
  • 3
    Why are you citing C++ when this is a C question? – ad absurdum Nov 24 '17 at 16:26
  • @DavidBowling If the rules differ between C++ and C in this case you are welcome to provide a citation. – Emily L. Nov 26 '17 at 13:32
  • 4
    That just dodges the question. Why would anyone cite a C++ standard in relation to a question about C? Someone who wants to make sense of this then has to go consult the right Standard to be certain that they agree on this point. Or one could just roll over and say, "well, if it's true in C++ it must be true in C...." – ad absurdum Nov 26 '17 at 15:23
  • 2
    @davidbowling I forgot that it was C when I answered a comment two years after the answer was written, please forgive me being human. I do not have the time or motivation to find the right quote, you are welcome to improve the answer or provide the relevant quote or counter quote. – Emily L. Nov 26 '17 at 17:35
  • 2
    @EmilyL. -- that makes perfect sense, and it does not affect the answer anyway, only the comments. AFAIK, both Standards say pretty much the same thing on this count. The only thing I would take issue with is that behavior is _implementation-defined_ ([not UB](https://stackoverflow.com/questions/8932707/what-are-anonymous-structs-and-unions-useful-for-in-c11/26361366?noredirect=1#comment67796252_26361366), I think) due to possible padding. But, this is still a typical use case in practice and so seems a good answer to the question. – ad absurdum Nov 26 '17 at 17:44
  • 4
    Why do you need the outer struct? Why can't you typedef the union directly to `vec3d_t`? – Mad Physicist May 11 '20 at 23:57
13
struct bla {
    struct { int a; int b; };
    int c;
};

the type struct bla has a member of a C11 anonymous structure type.

struct { int a; int b; } has no tag and the object has no name: it is an anonymous structure type.

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
ouah
  • 142,963
  • 15
  • 272
  • 331
  • 11
    And what is the difference to just do `struct bla {int a;intb;intc;};`? – dhein Dec 09 '13 at 15:27
  • 4
    @Zaibis there is no difference to access the members of the structure but the version with the anonymous structure holds an extra information: there is some logical relationship between `a` and `b` that doesn't exist with `c` – ouah Dec 09 '13 at 22:06
  • can you explain what this information could be usefull for? is this a thing of performance? or what is it about? – dhein Dec 09 '13 at 22:16
  • @Zaibis take the example of an API, this information could be useful for the reader as it exposes a different information on the nature of `a` and `b`. – ouah Dec 09 '13 at 22:19
  • 2
    @Zaibis - The inner struct can be named and used on its own. One use case would be implementing inheritance (the outer struct extends the inner one). – martinkunev Apr 27 '15 at 15:49
  • @martinkunev: are you sure about that it behaves like that? – dhein Apr 27 '15 at 16:32
  • @Zaibis Yes, the standard (C99 6.7.2.1) guarantees that a pointer to a struct can be used as a pointer to its first member (with appropriate casting). – martinkunev Apr 28 '15 at 08:13
  • @martinkunev: Of cause that is possible. but you said this is a way of implementing inheritance. that would mean the inner one would have its own `a`. how ever to acces it. – dhein Apr 28 '15 at 09:14
  • @Zaibis I'm not sure I understand what you are asking. You can access the fields of the inner struct in exactly the same way as in the answer of ouah. – martinkunev Apr 28 '15 at 11:37
  • yeah, but I that has nothing to do with inerhitance. – dhein Apr 28 '15 at 12:35
  • 1
    The benefit to this would be with bitfields, to pack the struct with variable length integers taking up the same space as a single int. – Kevin Oct 23 '19 at 18:24
8

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.

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 r. i.e:

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

Dylan Gentile
  • 146
  • 1
  • 5
  • 2
    Perhaps you are just showing that you can do this but why would you use the outside struct? If you remove the outside struct and typedef the union, your code appears to behave the same. – Apprentice_Programmer Jul 20 '21 at 14:57
5

I'm not sure why C11 allows anonymous structures inside structures. But Linux uses it with 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;

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

I.e. a language extension / compiler plugin to randomize field order (ASLR-style exploit "hardening"):

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
};
sourcejedi
  • 3,051
  • 2
  • 24
  • 42
0

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 e.a,f.d.b,etc.

(I added the inner struct, because I think that this is one of the most usages of anonymous structs)

asaelr
  • 5,438
  • 1
  • 16
  • 22
  • 1
    This was correct and submitted a little earlier than the one I accepted. Sorry, that one 'explained' it a little better but, now that I understand, I see that this is a pretty good answer. – griotspeak Jan 19 '12 at 20:52
  • 6
    This is not the feature being discussed, and this code is not making use of anything new to C11. The structs in the example are *not* anonymous: they have the names `.d`, `e` and `f` respectively. They have anonymous types, but that's something different. – Alex Celeste Mar 23 '17 at 15:42
  • anonymous structs has no identifier and no tag. – Undefined Behavior Jan 09 '19 at 13:17