Suppose I have the following unsigned long val = 0xfedcba9876543210
and I want to change the 16 least significant bits to 0xabcd
. So, the original value will be changed to unsigned long val = 0xfedcba987654abcd
. I already have a function get
that can return 0x3210
, but I'm unsure how I can change this section of the value to 0xabcd
. For more context, here is what I am trying to implement:
void set_pattern(unsigned long* val, int i, unsigned short new_pattern) {
// my attempt
unsigned short old_pattern = get(val, i); // ex: returns 0x3210 when i = 0
unsigned short* ptr = NULL;
ptr = &old_pattern;
*ptr = new_pattern;
}
When I tried my attempt, it seemed to not set the new pattern as I expected. Any help or feedback is appreciated in helping me gain a better understanding of C.
To explain Nate's comment, you want to apply a bitmask to zero out the relevant bits, then apply the new bits with a bitwise or.
Let's do it with 32 bits and you want to change the the least 8.
Apply a bitmask to turn the least 8 bits to 0. val = val & ~0xff
. ~0xff
is 0xffffff00
. Since 0 & x = 0, all the filled in bits will retain their value, and all the 0's will become 0 no matter their original value.
0x12345678 val
AND 0xffffff00 ~0xff
= 0x12345600
Now that the relevant bits have been masked out, turned to 0, we can overwrite just them with a bitwise or. val = val | new_value
. x | 0 = x. The irrelevant bits of new_value are 0. x | 0 = x. They will retain val's value. The relevant bits of val are 0. 0 | x = x. They will retain new_value's value.
0x12345600 val
OR 0x000000ef new_value
= 0x123456ef
If you want to replace different bits, you need to shift the bitmask and replacement value the appropriate amount.
Let's say we want to replace 56 with ef instead. Each hex character is 4 bits, so we need to left shift both the bitmask and replacement value by 8 bits.
0x12345678 val
AND 0xffff00ff ~(0xff << 8) == ~0xff00
= 0x12340078
0x12340078 val
OR 0x0000ef00 new_value << 8 == 0xef00
= 0x1234ef78