I have a struct:
typedef struct {
uint8_t month; // 1..12 [4 bits]
uint8_t date; // 1..31 [5 bits]
uint8_t hour; // 00..23 [5 bits]
uint8_t minute; // 00..59 [6 bits]
uint8_t second; // 00..59 [6 bits]
} TimeStamp;
but I would like to pack it so it only consumes four bytes instead of five.
Is there a way of shifting the bits to create a tighter struct?
It might not seem much, but it is going into EEPROM, so one byte saved is an extra 512 bytes in a 4 KB page (and I can use those extra six bits left over for something else too).
You're looking for bitfields.
They look like this:
typedef struct {
uint32_t month : 4; // 1..12 [4 bits]
uint32_t date : 5; // 1..31 [5 bits]
uint32_t hour : 5; // 00..23 [5 bits]
uint32_t minute : 6; // 00..59 [6 bits]
uint32_t second : 6; // 00..59 [6 bits]
} TimeStamp;
Depending on your compiler, in order to fit into four bytes with no padding, the size of the members must be four bytes (i.e. uint32_t
) in this case. Otherwise, the struct members will get padded to not overflow on each byte boundary, resulting in a struct of five bytes, if using uint8_t
. Using this as a general rule should help prevent compiler discrepancies.
Here's an MSDN link that goes a bit in depth into bitfields:
C++ Bit Fields
Bitfields are one "right" way to do this in general, but why not just store seconds since the start of the year instead? 4 bytes is enough to comfortably store these; in fact, 4 bytes are enough to store the seconds between 1970 and 2038. Getting the other information out of it is then a simple exercise as long as you know the current year (which you could store together with the rest of the information as long as the range of times you're interested in covers less than 70 years (and even then you could just group timestamps into 68 year ranges and store an offset for each range).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With