Take the hypotetical case that I have four unsigned char
variables, and for whatever reason, in all of those variables, I never use the last bit, so I have four bits that I can use for another thing, without the need of having an extra variable.
e.g: example. How to use those bits that are highlighted in red.
I think that I will have to use math with bitwise operators, but I don't know if there is any right or wrong way.
Note: I'm trying to do this in C, so if you use C in the example, I'll be very grateful, but I think that other languages won't differ so much from the C approach.
In general C provides an abstract machine (to hide the underlying details) and converts your code into something that may be radically different. For the C abstract machine; an unsigned char
has CHAR_BITS
bits (maybe not 8 bits), structures (including bitfields) may have any amount of extra padding (whatever the compiler felt like), etc.
If you care about the underlying details; then you have to break through the abstraction. In your case, this might mean (e.g.) using a uint32_t
and doing shifting and masking yourself; so that you can have a guarantee that the compiler converts it into what you want.
Example (untested and relatively awful - could use defines and macros):
uint32_t demoPackedValue = ((uint32_t)'a' << 24) | ((uint32_t)'b' << 16) ((uint32_t)'c' << 8) | (uint32_t)'d';
char getChar1(uint32_t packedValue) {
return packedValue & 0x0000007FUL;
}
uint32_t setChar1(uint32_t packedValue, char c) {
packedvalue = (packedvalue & 0xFFFFFF80UL) | ((uint32_t)c);
return packedvalue;
}
int getBit1(uint32_t packedValue) {
return !!(packedValue & 0x00000080UL);
}
uint32_t setBit1(uint32_t packedValue, int value) {
if(value == 0) {
packedValue &= 0xFFFFFF7FUL;
} else {
packedValue |= 0x00000080UL;
}
return packedvalue;
}
char getChar2(uint32_t packedValue) {
return (packedValue & 0x00007F00UL) >> 8;
}
uint32_t setChar2(uint32_t packedValue, char c) {
packedvalue = (packedvalue & 0xFFFF80FFUL) | ((uint32_t)c << 8);
return packedvalue;
}
Of course that's also likely to harm performance (unless you have a very large amount of data and the extra cost of shifting/masking can be justified).