Please note my comments, the question is still unanswered.
I have the following which I can't change:
unsigned long addr=142;
u16 offset_low, offset_middle;
u32 offset_high;
I want to set offset_low
for low 16 bits, offset_middle
for mid 16 bits and offset_high
for higher 32 bits of addr
.
So I wrote:
offset_low = addr & 0xFFFF;
offset_middle = addr & 0xFFFF0000;
offset_high = addr & 0xFFFFFFFF0000;
Is this right? Is there any clear way to do it instead of wiriting so many F?
Why I think it's not right?
I am working with little endian, so when doing addr & 0xFFFF0000; I will get the mid bits but with zeros and it may load the zeros instead of non-zeroes.
For your purpose you must shift the masked values:
unsigned long addr = 142; // 64-bit on the target system
uint16_t offset_low = addr & 0xFFFF;
uint16_t offset_middle = (addr & 0xFFFF0000) >> 16;
uint32_t offset_high = (addr & 0xFFFFFFFF00000000) >> 32;
Note that since you extract exactly 16 and 32 bits to variables with the same size, masking can be omitted:
uint64_t addr = 142;
uint16_t offset_low = addr;
uint16_t offset_middle = addr >> 16;
uint32_t offset_high = addr >> 32;
The order of bytes in memory (little endian vs big endian) is irrelevant for this question. You could read the specific parts from memory using this knowledge, reading the first 2 bytes for offset_low
, the next 2 for offset_middle
and the next 4 for offset_high
, but extracting from the full 64-bit value is performed the same for both architectures.