Author Topic: Union of Structures  (Read 2398 times)

0 Members and 1 Guest are viewing this topic.

Offline Ground_LoopTopic starter

  • Frequent Contributor
  • **
  • Posts: 666
  • Country: us
Union of Structures
« on: October 21, 2020, 11:24:36 am »
I'm having trouble understanding what is happening with the definition below:

Code: [Select]
#define U1MODE U1MODE
extern volatile uint16_t  U1MODE __attribute__((__sfr__));
__extension__ typedef struct tagU1MODEBITS {
  union {
    struct {
      uint16_t STSEL:1;
      uint16_t PDSEL:2;
      uint16_t BRGH:1;
      uint16_t RXINV:1;
      uint16_t ABAUD:1;
      uint16_t LPBACK:1;
      uint16_t WAKE:1;
      uint16_t UEN:2;
      uint16_t :1;
      uint16_t RTSMD:1;
      uint16_t IREN:1;
      uint16_t USIDL:1;
      uint16_t :1;
      uint16_t UARTEN:1;
    };
    struct {
      uint16_t :1;
      uint16_t PDSEL0:1;
      uint16_t PDSEL1:1;
      uint16_t :5;
      uint16_t UEN0:1;
      uint16_t UEN1:1;
    };
  };
} U1MODEBITS;
extern volatile U1MODEBITS U1MODEbits __attribute__((__sfr__));

I get unions, structures and attributes, but the two structures defined under the union baffles me.  What is goin on here?
There's no point getting old if you don't have stories.
 

Offline greenpossum

  • Frequent Contributor
  • **
  • Posts: 408
  • Country: au
Re: Union of Structures
« Reply #1 on: October 21, 2020, 11:31:59 am »
Bitfields.
 

Offline Ground_LoopTopic starter

  • Frequent Contributor
  • **
  • Posts: 666
  • Country: us
Re: Union of Structures
« Reply #2 on: October 21, 2020, 11:34:16 am »
Bitfields.

And I know what bit fields are.  What is the purpose and usage of two structures
There's no point getting old if you don't have stories.
 

Offline ledtester

  • Super Contributor
  • ***
  • Posts: 3248
  • Country: us
Re: Union of Structures
« Reply #3 on: October 21, 2020, 11:39:24 am »
You can access .PDSEL and get 2 bits or you can access .PDSEL0 and .PDSEL1 individually.

Same with .UEN.
 

Offline Ground_LoopTopic starter

  • Frequent Contributor
  • **
  • Posts: 666
  • Country: us
Re: Union of Structures
« Reply #4 on: October 21, 2020, 11:45:27 am »
You can access .PDSEL and get 2 bits or you can access .PDSEL0 and .PDSEL1 individually.

Same with .UEN.

Ok now I see the bit positions are the same for both structures.  Thanks for that.
There's no point getting old if you don't have stories.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1772
  • Country: se
Re: Union of Structures
« Reply #5 on: October 21, 2020, 11:58:04 am »
Here, the use of unnamed nested structures and unions (standard since C11) allows to address the various field without the need of specifying a redundant structure or union object name.

And bitfields, yes.
Bitfields (even excluding the various __attribute__ __extension__ stuff used here) are very, very, very implementation dependent.
Even the declaration as uint16_t is not exactly standard (allowed as an implementation dependent extension), as the standard only foresees int, (un)signed int and _Bool.
Frankly, it makes no sense to me to declare the fields with a fixed size type (which is not taken into account at all).
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8882
  • Country: fi
Re: Union of Structures
« Reply #6 on: October 21, 2020, 01:07:47 pm »
Alternative ways of access. Really, really handy. For example, sometimes you want to access a memory location as a 32-bit operation, sometimes you want to assign or read part of it as a, say, 8-bit signed integer, or even more fancier, a 5-bit signed integer. Doing that using unions and bitfields results in more readable and less error prone code compared to a massive hack of bit masking and shifting.

Sometimes different parts of documentation group configuration register bits differently. For example, STM32 SPI has a 16-bit transfer size register as an upper half of a control register. You may want to use the control register under the name given on the datasheet, but you may also want to access SPI->TSIZE = 42; for convenience and clarity.

Another good example would be reading 57 bytes of calibration data out of a device: you just want to access them as calib.u8[idx] or calib.u32[idx] depending on the communication data width available; but after the readout, you want to access it using calib.voltage_offset or whatever.

Anonymous structs inside union are great because you don't need to access thing.done_one_way.blargh and thing.done_another_way.blorgh, just using thing.blargh and thing.blorgh is enough.

Initializers get a bit tricky, though, you need quite some extra {{{}}}.

Do note that with bitfields, you rely on particular compiler putting them in particular order, possibly with no proper attributes to control the order available. Further limiting yourself to not using bitfields allows almost portable solution given that any decent compiler have had the concept of packed struct for a long time. The syntax for giving that attribute varies compiler to compiler, but you can #define that out for simple porting.

A pedantic note is worth mentioning: C standard at least originally - I haven't looked if this has been fixed - said that union cannot be used for such purpose; by writing one element in the union, you are supposed to only read the same element back, not access the same data through the another element; only rendering the union useful for memory saving of static objects, pretty useless. In practice, this is meaningless; everybody uses unions in the "forbidden" way because that's actually very useful, and any decent compiler works correctly (if it doesn't, and if it's being maintained, it will get fixed due to widespread usage of union).

As a general note, sometimes on microcontrollers, the actual memory access instruction width matters. You may really NEED to read or write a 8-bit AHB/APB bus operation, instead of writing the full 32-bit register, or even worse, read-modify-write.
« Last Edit: October 21, 2020, 01:11:11 pm by Siwastaja »
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1772
  • Country: se
Re: Union of Structures
« Reply #7 on: October 21, 2020, 01:48:29 pm »
Another good example would be reading 57 bytes of calibration data out of a device: you just want to access them as calib.u8[idx] or calib.u32[idx] depending on the communication data width available; but after the readout, you want to access it using calib.voltage_offset or whatever.
[...]
A pedantic note is worth mentioning: C standard at least originally - I haven't looked if this has been fixed - said that union cannot be used for such purpose; by writing one element in the union, you are supposed to only read the same element back, not access the same data through the another element;
I just did a very similar thing for reading/writing part of configuration and status of an RTC through I2C in a clearer manner.

And about the standards:
Something did change between ISO/IEC 9899:1999 and ISO/IEC 9899:2011.

'6.2.6 Representations of types' is unchanged.
For both, an array of unsigned is guaranteed to never to be a trap representation, so it's always possible to read the object representation as a sequence of "bytes".

In C11 this footnote in '6.5.2.3, Structure and union members' has been added:
Quote
95) If the member used to read the contents of a union object is not the same as the member last used to
store a value in the object, the appropriate part of the object representation of the value is reinterpreted
as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type
punning’’). This might be a trap representation.
I read this as condoning type punning, if one can guarantee never to incur in a trap representation.
This guarantee can sometimes be inferred by other constraints on the involved types.

C18 (aka C17), ISO/IEC 9899:2018, does not change in this respect.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline Ground_LoopTopic starter

  • Frequent Contributor
  • **
  • Posts: 666
  • Country: us
Re: Union of Structures
« Reply #8 on: October 22, 2020, 02:07:11 am »
Thanks guys it's clear now.  This helps a lot.
There's no point getting old if you don't have stories.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf