C如何读取中间位?

C how to read middle bits?

请注意我的评论,问题仍未得到解答。

我有以下无法更改

unsigned long addr=142;
u16 offset_low, offset_middle;
u32 offset_high;

我想为addr的低16位设置offset_low,中16位设置offset_middle,高32位设置offset_high

所以我写道:

offset_low = addr & 0xFFFF;
offset_middle = addr & 0xFFFF0000;
offset_high = addr & 0xFFFFFFFF0000;

这样对吗?有什么明确的方法可以代替写那么多 F 吗?

为什么我觉得不对?

我正在使用 little endian,所以在执行 addr & 0xFFFF0000 时;我将得到中间位但带有零,它可能会加载零而不是非零。

为了您的目的,您必须移动屏蔽值:

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;

请注意,由于您恰好将 16 位和 32 位提取到具有相同大小的变量,因此可以省略掩码:

uint64_t addr = 142;
uint16_t offset_low = addr;
uint16_t offset_middle = addr >> 16;
uint32_t offset_high = addr >> 32;

内存中的字节顺序(小端与大端)与这个问题无关。您可以使用这些知识从内存中读取特定部分,读取 offset_low 的前 2 个字节,offset_middle 的后 2 个字节和 offset_high 的下 4 个字节,但从完整的 64 个字节中提取-bit 值对两种体系结构执行相同。

按所需位移动 1,然后减去 1 将得到位序列 1,除非您希望整数类型中的最高(最高)位为 1。

假设环境中的unsigned long有33位以上,可以这样写:

offset_low = addr & ((1UL << 16) - 1);
offset_middle = (addr >> 16) & ((1UL << 16) - 1);
offset_high = (addr >> 32) & ((1UL << 32) - 1);

Is this right?

不完全是,这些是正确的:

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

您没有将结果向右移动(而您的高点恰恰是错误的)。

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.

字节序在代码中无关紧要,因为代码在同一台机器上运行。它只在序列化期间很重要,在序列化期间,您在一台机器上写入流并从另一台机器读取另一种字节序,从而产生垃圾。