C how to read middle bits?

1

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.

c
bit
ram
endianness
asked on Stack Overflow May 19, 2021 by (unknown user) • edited May 19, 2021 by (unknown user)

3 Answers

2

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.

answered on Stack Overflow May 19, 2021 by chqrlie • edited May 19, 2021 by chqrlie
0

Shifting one by desired bits and then subtracting one will give sequence of bits 1 unless you want the top (most significant) bit in the integer type to be one.

Assuming that unsigned long in the environment has 33 bits or more, it can be written like this:

offset_low = addr & ((1UL << 16) - 1);
offset_middle = (addr >> 16) & ((1UL << 16) - 1);
offset_high = (addr >> 32) & ((1UL << 32) - 1);
answered on Stack Overflow May 19, 2021 by MikeCAT
0

Is this right?

Not quite, these would be correct:

offset_low = addr & 0xFFFF;
offset_middle = (addr >> 16) & 0xFFFF;
offset_high = addr >> 32;

You didn't shift your results to the right (and your high was just wrong).

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.

The endianness doesn't matter in code, because code runs on the same machine. It only matters during serialization, where you write to a stream on one machine and read from another machine of another endianness, thus getting garbage.

answered on Stack Overflow May 19, 2021 by Blindy

User contributions licensed under CC BY-SA 3.0