FlexTapeDude
FlexTapeDude

Reputation: 41

Union of struct with one element vs union of element mplab pic32

I was looking at a pic 10 include file (p32mk1024gpk064.h) and was wondering why they added a struct with a single element instead of an union between a struct and an uint_32.

typedef union {
  struct {
    uint32_t RB0:1;
    uint32_t RB1:1;
    uint32_t RB2:1;
    uint32_t RB3:1;
    uint32_t RB4:1;
    uint32_t RB5:1;
    uint32_t RB6:1;
    uint32_t RB7:1;
    uint32_t RB8:1;
    uint32_t RB9:1;
    uint32_t RB10:1;
    uint32_t RB11:1;
    uint32_t RB12:1;
    uint32_t RB13:1;
    uint32_t RB14:1;
    uint32_t RB15:1;
  };
  struct {
    uint32_t w:32;
  };
} __PORTBbits_t;

VS

typedef union {
  struct {
    uint32_t RB0:1;
    uint32_t RB1:1;
    uint32_t RB2:1;
    uint32_t RB3:1;
    uint32_t RB4:1;
    uint32_t RB5:1;
    uint32_t RB6:1;
    uint32_t RB7:1;
    uint32_t RB8:1;
    uint32_t RB9:1;
    uint32_t RB10:1;
    uint32_t RB11:1;
    uint32_t RB12:1;
    uint32_t RB13:1;
    uint32_t RB14:1;
    uint32_t RB15:1;
  };
  uint32_t w:32;
} __PORTBbits_t;

I tried compiling both version and they both work, Idk what's the point of the second struct

Upvotes: 2

Views: 81

Answers (2)

FlexTapeDude
FlexTapeDude

Reputation: 41

There's no difference. They are functionally the same.

Upvotes: 2

pmacfarlane
pmacfarlane

Reputation: 4317

In the before time (before C11), neither of these data types would have been valid. Every field in a structure or union would need a name. If we take your first example, and cut it down to a single bit in the first struct, you'd have:

typedef union {
  struct {
    uint32_t RB0:1;
  };
  struct {
    uint32_t w:32;
  };
} __PORTBbits_t;

Neither of the two structs are given a name, and this would be invalid. You'd need to have something like:

typedef union {
  struct {
    uint32_t RB0:1;
  } bits;
  struct {
    uint32_t w:32;
  } word;
} __PORTBbits_t;

and you'd access those like:

__PORTBbits_t foo;
uint32_t bar = foo.word.w; // Ignore all the UB for uninitialised variables
uint32_t bit = foo.bits.RB0;

C11 allows anonymous structs, so long as the fields are all unique. This lets you skip naming internal structures. In that case, both of your examples would be valid, and you could access them like:

__PORTBbits_t foo;
uint32_t bar = foo.w;
uint32_t baz = foo.RB0;

Your second example both uses and does not use this feature. Cropped as before you have:

typedef union {
  struct {
    uint32_t RB0:1;
  };
  uint32_t w:32;
} __PORTBbits_t;

Here, we have RB0 used as part of an anonymous structure, but w as an explicitly named field (not in an anonymous structure).

Both examples use the C11 syntax though, there is no reason to prefer one over the other, they behave exactly the same. The first example is at least consistent and symmetrical regarding the structure fields.

TL/DR; Both versions are exactly the same, in practice. There may be stylistic (or company policy) reasons to prefer one over the other, but the generated code will be the same.

Upvotes: 2

Related Questions