I am currently trying to figure out an elegant and convenient way to store 4 14-bit values and 1 8-bit value within a 64 bit boundary.
something like this:
typedef struct my64bit{
unsigned data1 : 14;
unsigned data2 : 14;
unsigned data3 : 14;
unsigned data4 : 14;
unsigned other : 8;
}tmy64Bit;
later I want to create an array of these 'containers'
tmy64Bit myArray[1000];
so that I have a pointer "myArray" which points to 1000x64-bits of memory
this array is send via tcp to an embedded-linux SOCFPGA system where it should be copied (with correction of endianness and network byte order) into a specific memory (directly accessible from the fpga)
my problem is that the upper code doesn't create a 64-bit type
sizeof(tmy64Bit)
returns 12, so 12 bytes are allocated instead of 8
filling the struct with data and watching the memory (on my 64 bit Linux system) returns this
tmy64Bit test;
memset(&test,0,sizeof(tmy64Bit));
test.data1 = 0x3fff;
...
test.other = 0xAA;
Memory View:
after d1 written = 0xFF3F0000 00000000 00000000
after d2 written = 0xFFFFFF0F 00000000 00000000
after d3 written = 0xFFFFFF0F FF3F0000 00000000
after d4 written = 0xFFFFFF0F FFFFFF0F 00000000
after o written = 0xFFFFFF0F FFFFFF0F AA000000
so the first 2 14 bit variables are stored correctly but then padding fills up the last half-byte and at the end the last byte needs to be stored in a new 64 bit cell
another approach would be
typedef struct my2nd64Bit{
uint8_t data[7];
uint8_t other;
}tmy2nd64Bit;
where a
sizeof(tmy2nd64Bit)
returns an 8 (which was expected)
This generates correctly padded structure, but storing the 14 bit always involves a lot of bitshifting and masking
This is what you want :
typedef struct my64bit{
uint64_t data1 : 14;
uint64_t data2 : 14;
uint64_t data3 : 14;
uint64_t data4 : 14;
uint64_t other : 8;
}tmy64Bit;
unsigned
means unsigned int
, and this type is 32-bit on most systems. This will cause padding because the individual fields won't be allowed to cross 32-bit boundaries. Using a 64-bit member type won't add padding for this case (you don't cross any 64-bit boundary).
As for any question about bit-fields, you need to remember that most of the bit-field mechanics are implementation defined, which means that if you want to use that, you should check that you actually get what you want. Also, if you plan to use another compiler, check that the behavior is the same (usually it is, but maybe not on exotic platforms). If you properly check, this is safe to use (not undefined behavior), but you might want to use a more portable way, using bit operations for example.