bit field/union help

so I am conceptually trying to create a union of a 64 bit number with an array of (4 bit) nibbles, but I cannot seem to get it properly aligned on my UNO:

constexpr uint64_t SOME_VALUE = ~0x0ULL;  //  0xFFFFFFFFFFFFFFFFULL; 

struct Nibble{
  uint8_t a: 4;
};

union MyUnion {
  uint64_t hash;
  Nibble nibble[16];
};

MyUnion example = {SOME_VALUE};

void setup() 
{
  Serial.begin(9600);
  Serial.println(sizeof(example));
  //example.hash = SOME_VALUE;
  for (int i = 0; i < 16; i++){
    Serial.print(F("Nibble "));
    Serial.print(i < 10? " " : "");
    Serial.print(i);
    Serial.print(F(":\t"));
    Serial.println(example.nibble[i].a);
  }
}

void loop() 
{

}

output:

16
Nibble  0:  15
Nibble  1:  15
Nibble  2:  15
Nibble  3:  15
Nibble  4:  15
Nibble  5:  15
Nibble  6:  15
Nibble  7:  15
Nibble  8:  0
Nibble  9:  0
Nibble 10:  0
Nibble 11:  0
Nibble 12:  0
Nibble 13:  0
Nibble 14:  0
Nibble 15:  0

is this possible?

Does tilde ~ work on ULL ? https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-complement-operator

6v6gt:
Does tilde ~ work on ULL ? Bitwise and shift operators - perform boolean (AND, NOT, OR, XOR) and shift operations on individual bits in integral types - C# | Microsoft Learn

I initialized with the more verbose OxFFFFFFFFFFFFFFFF and got the same output.

(that's why I included it int eh example)

Add this sanity check...

  Serial.println(sizeof(example));

The expected output is 8.

6v6gt:
Does tilde ~ work on ULL ? Bitwise and shift operators - perform boolean (AND, NOT, OR, XOR) and shift operations on individual bits in integral types - C# | Microsoft Learn

That's a reference for C#, not C/C++; not sure if ~ isnt supported for ULL in arduino.

Print the value that you set it to, and make sure is 0xFFFFFFFFFFFFFFFF not 0x00000000FFFFFFFF.

You really want to find the border of the 'c' language and the compiler ??? :stuck_out_tongue:

Make the constant: 0x0123456789ABCDEFULL, then you see.
What happens if you do sizeof(Nibble) ? Do you expect that to be 0.5 bytes in size ? No, it is one byte in size.
The problem is not the bit fields, but the struct. The struct is placed at a byte boundery. That is why the size is 16 bytes instead of 8 bytes.

As far as I know, it is not possible to make an array of a bitfield variable.
At this moment I don't have a solution for an array of nibbles in a struct or union.

you mean add another one?

Koepel:
At this moment I don't have a solution for an array of nibbles in a struct or union.

It may not be do-able... I think we are in agreement that we cannot align the nibbles to less than a byte.

:frowning:

BulldogLowell:
you mean add another one?

Oops. Sorry about that.

The conclusion is that it is not possible :cry:

It is possible without array, but that is not helping.

struct MyNibbles
{
  unsigned int n0  :4;
  unsigned int n1  :4;
  unsigned int n2  :4;
  unsigned int n3  :4;
  unsigned int n4  :4;
  unsigned int n5  :4;
  unsigned int n6  :4;
  unsigned int n7  :4;
  unsigned int n8  :4;
  unsigned int n9  :4;
  unsigned int n10 :4;
  unsigned int n11 :4;
  unsigned int n12 :4;
  unsigned int n13 :4;
  unsigned int n14 :4;
  unsigned int n15 :4;
};

One could easily enough make a helper function, eg, an array of 8 bytes in the struct, then

byte getNibble(byte n)
return example.Bytes[n>>1]>>(n|1?4:0)
}

A macro can handle a 8-bit byte or 16-bit integer or even a uint64_t in the same way:

constexpr uint64_t some_value = 0x0123456789ABCDEFULL;

#define NIBBLE(a,b) ((byte)((a)>>((b)*4))&0x0F)

void setup()
{
  Serial.begin(9600);
  Serial.println(sizeof(some_value));
  
  for (int i = 0; i < 16; i++)
  {
    Serial.print(F("Nibble "));
    Serial.print(i < 10? " " : "");
    Serial.print(i);
    Serial.print(F(":\t"));
    Serial.print(NIBBLE(some_value, i), HEX);
    Serial.println();
  }
}

void loop()
{
}

Koepel:
A macro can handle a 8-bit byte or 16-bit integer or even a uint64_t in the same way:

but not run-time...

BTW: proper C++ way of doing what you did:

constexpr uint64_t SOME_VALUE = ~0x0ULL;  // 0xFFFFFFFFFFFFFFFFULL; 
constexpr uint8_t NIBBLE(uint64_t a,uint8_t b) {return (byte)((a)>>((b)*4))&0x0F;};

void setup()
{
  Serial.begin(9600);
  Serial.println(sizeof(SOME_VALUE));
  
  for (int i = 0; i < 16; i++)
  {
    Serial.print(F("Nibble "));
    Serial.print(i < 10? " " : "");
    Serial.print(i);
    Serial.print(F(":\t"));
    Serial.print(NIBBLE(SOME_VALUE, i), HEX);
    Serial.println();
  }
}