1

我有一个 16 位地址,我需要将其拆分为 15-8 的页码和 7-0 的偏移量。

所以,我猜我可以对它进行按位运算?

假设0xBEEF是需要拆分的地址。

页码:
0xBEEF & 0xFF80= 1011 1110 1110 1111 & 1111 1111 1000 0000 = 1011 1110 1000 0000 = 0xBE80

抵消:
0xBEEF & 0x007F= 1011 1110 1110 1111 & 0000 0000 0111 1111 = 0000 0000 0110 1111 = 0x006F

除了 C 中宏的按位算术之外,还有其他方法可以做到这一点吗?

4

3 回答 3

4

您可以在大多数程序中使用位移运算符。

top8 = 0xABCD >> 8; bottom8 = 0xABCD & 0x00FF;

这会给你top8 = 0x00ABbottom8 = 0x00CD

请注意,您不必将它们移动 8 位,它可以是任何东西。

于 2013-03-10T07:06:36.460 回答
3

是的,有几种不同的方法可以做到这一点,但我不推荐任何一种

在 C 中将 16 位值分成高位和低位是一件非常棘手的事情,因为位的顺序取决于硬件的字节序。如果你的系统是大端系统,高位将被存储在第二个,如果你的系统是小端,高位首先被存储。

让我们以 0xBEEF 为例,这是它在内存中的样子:

little endian     |     big endian
-------------------------------------
... EF BE ...     |     ... BE EF ...

如果您使用位算术来分隔这两个字节,则不必关心它们在内存中的顺序,但实际上任何其他方法都会受到影响,需要您以某种方式检测字节序并有条件地编程以获得可移植的解决方案.

话虽如此,如果您不关心可移植性,可以使用以下几种替代方法:

1.) 演员表

这种方法基本上是icepack提出的。您获取变量的地址,将其转换为指向 char 的指针,并将其视为数组,以获取单独的字节。

2.) 工会

具有与演员相同的效果,您还可以创建一个这样的联合:

union myvalue
  {
    uint16_t value;
    uint8_t bytes[2];
  }

能够分别寻址字节和值

3.) 反过来

另一种完全不同的方法是首先将您的 16 位数据存储在一个无符号字符数组中,您购买的是地址上的计算开销,但您不需要分隔字节。当然,如果地址是某种计算的结果,并且无论如何您都必须拆分字节,那么这将不再有意义。

最后一句话 - 如果您关心代码的可移植性,请使用 AND 和 shift 来提取字节。

于 2013-03-10T07:53:59.267 回答
2

这是一种无需位操作即可执行此操作的方法:

对于大端系统:

#define OFFSET(x) (*(unsigned char *)x)
#define PAGE(x)   (*((unsigned char *)x + 1))

对于 little-endian 系统,请切换 和 的OFFSET定义PAGE

请注意 char 在您的系统中是 8 位的假设(如果不是出于某种奇怪的原因,请使用适当的 8 位类型)。

于 2013-03-10T07:16:22.773 回答