C分裂位

C分裂位,c,macros,C,Macros,我有一个16位的地址,我需要把它分成15-8页的页码和7-0页的偏移量 所以,我猜我可以对它进行位运算 假设0xBEEF是需要拆分的地址 页码: 0xBEEF&0xFF80=101111011101&11111111000000=1011110100000000=0xBE80 偏移量: 0xBEEF&0x007F=101111011111&0000 0000 0111111=0000 0000 0000 011011111=0x006F 除了C中宏的按位运算外,还有其他不同的方法来实现这一点吗

我有一个16位的地址,我需要把它分成15-8页的页码和7-0页的偏移量

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

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

页码: 0xBEEF&0xFF80=101111011101&11111111000000=1011110100000000=0xBE80

偏移量: 0xBEEF&0x007F=101111011111&0000 0000 0111111=0000 0000 0000 011011111=0x006F


除了C中宏的按位运算外,还有其他不同的方法来实现这一点吗

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

top8=0xABCD>>8; 底部8=0xABCD&0x00FF

这将为您提供top8=0x00AB和bottom8=0x00CD


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

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

top8=0xABCD>>8; 底部8=0xABCD&0x00FF

这将为您提供top8=0x00AB和bottom8=0x00CD


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

这里有一种不需要进行位操作的方法:

对于big-endian系统:

#define OFFSET(x) (*(unsigned char *)x)
#define PAGE(x)   (*((unsigned char *)x + 1))
对于little endian系统,切换偏移量和页面的定义


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

这里有一种不用位操作的方法:

对于big-endian系统:

#define OFFSET(x) (*(unsigned char *)x)
#define PAGE(x)   (*((unsigned char *)x + 1))
对于little endian系统,切换偏移量和页面的定义


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

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

在C语言中,将16位值分成高位和低位是一件非常棘手的事情,因为位的顺序取决于硬件的端性。如果您的系统是big-endian系统,高位将存储在第二位,如果您的系统是little-endian系统,高位将首先存储

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

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

话虽如此,如果您不关心可移植性,这里有两种选择:

一,。演员阵容

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

二,。工会

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

union myvalue
  {
    uint16_t value;
    uint8_t bytes[2];
  }
能够分别寻址字节和值

三,。相反

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


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

是的,有几种不同的方法,但我不推荐任何一种

在C语言中,将16位值分成高位和低位是一件非常棘手的事情,因为位的顺序取决于硬件的端性。如果您的系统是big-endian系统,高位将存储在第二位,如果您的系统是little-endian系统,高位将首先存储

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

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

话虽如此,如果您不关心可移植性,这里有两种选择:

一,。演员阵容

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

二,。工会

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

union myvalue
  {
    uint16_t value;
    uint8_t bytes[2];
  }
能够分别寻址字节和值

三,。相反

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


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

您可以使用位结构,但在您的情况下,您使用的位操作是很好的选择。通常的字是隐藏的,而不是拆分的。您是否意识到您在问题中说您想要拆分位15-8和7-0,你的代码实际上拆分了15-7位和6-0位?你可以使用bitwise struct,但在你的例子中,你使用的bitwise操作是一个很好的选择通常的单词是屏蔽的而不是拆分的。你知道你在问题中说你想拆分bite 15-8和7-0吗,你的代码实际上是将15-7位和6-0位分开的?除了按位算术之外,这是如何保持的?位移位只涉及一个变量,因此不是算术。根据定义,算术至少需要两个主对象。但我听到你说的,这是一个灰色区域。你也使用操作符&。但这并不是点算术和位算术是相互正交的,它们之间没有直接的关系。关于&运算,你是完全正确的。但我一直认为使用移位是因为它比标准的按位算术或,AND,XOR&NOT需要更少的参数。请注意,我所说的是逻辑移位,而不是算术移位。它肯定是。这个讨论没有任何意义,让我们停止讨论,除了按位算术之外,它还有什么意义?位移位只涉及一个变量,因此不是算术。根据定义,算术至少需要两个主对象。但我听到你说的,这是一个灰色区域。你也使用操作符&。但这并不是点算术和位算术是相互正交的,它们之间没有直接的关系。关于&运算,你是完全正确的。但我一直认为使用移位是因为它比标准的按位算术或,AND,XOR&NOT需要更少的参数。请注意,我所说的是逻辑移位,而不是算术移位。它肯定是。这场讨论没有结果,我们走吧stop@AndreasGrapentin谢谢,修好了。顺便说一句,这个建议并不被认为是完全可移植的-2个已经提到的可移植性问题,但可能还有更多。@AndreasGrapentin谢谢,修复了。顺便说一句,这个建议并不被认为是完全可移植的-2可移植性问题已经提到,但很可能还有更多。非常全面,写得很好!非常全面,写得很好!