Combining UNION and STRUCT for Easy Nybbling of Arduino Data in C/C++

This was a question I encountered recently – how to take a stream of bytes and break them into parts – not just individual bytes, but bits of bytes.

In this case, the code was 2 nybbles in a byte (yes, really, nybbles, where a nybble is 4 bits).

A simple solution is to use bit operators to split out the code:

unsigned int a = (data>>4) & 0xF; // top 4 bits
unsigned int b = data & 0xF; // bottom 4 bits

Why “& 0xF” in the first line? Because if your data is more than 8 bits, you want to remove the higher ones from the result (called masking), leaving only the single nybble of 4 bits.

The alternative is to use a union and a struct to combine the two:

union convertor
{
  struct
  {
    byte type: 4;
    byte number: 4;
  } pieces;
  byte whole;
};

Here, the union is between pieces and whole. whole is a byte (unsigned char, or 8 bits) and pieces is a structure of 4 bits (type) then 4 bits (number).

Because the values in a union share the same physical space, you just pop data in one end, and get it out the other:

union convertor data;
data.whole=215;
unsigned int a=data.pieces.type; // the type of each entry
unsigned int b=data.pieces.number; // the number of each entry

It works the other way, too:

union convertor data;
data.pieces.type=1;
data.pieces.number=15;
unsigned int result=data.whole; // type/number now one byte

Where unions and structs work well together is with complicated bitfield layouts. For example, say you have a 32 bit value that needs to swap nybbles in each byte (perhaps reading from an unusual data format). Then you could create a union for the whole thing, and swap very easily.

One option is this:

union convertor2
{
  struct
  {
    byte a1: 4;
    byte a2: 4;
    byte b1: 4;
    byte b2: 4;
    byte c1: 4;
    byte c2: 4;
    byte d1: 4;
    byte d2: 4;
  } nybble;
  unsigned long whole;
};

union convertor2 temp, data;
temp.whole=91303134;
data.nybble.a1 = temp.nybble.a2;
data.nybble.a2 = temp.nybble.a1;
data.nybble.b1 = temp.nybble.b2;
data.nybble.b2 = temp.nybble.b1;
data.nybble.c1 = temp.nybble.c2;
data.nybble.c2 = temp.nybble.c1;
data.nybble.d1 = temp.nybble.d2;
data.nybble.d2 = temp.nybble.d1;

data now contains the swapped values.

The result? unions provide a simple way to translate from one data entry to another – so give them a try.

3 thoughts on “Combining UNION and STRUCT for Easy Nybbling of Arduino Data in C/C++