c-从十六进制符号的任意一侧提取k位


int X = 0x1234ABCD;
int Y = 0xcdba4321;

// a) print the lower 10 bits of X in hex notation
int output1 = X & 0xFF;
printf("%Xn", output1);
// b) print the upper 12 bits of Y in hex notation
int output2 = Y >> 20;
printf("%Xn", output2);

我想用十六进制表示法打印X的低10位;由于十六进制中的每个字符都是4位,FF=8位,那么&用0x2FF获得十六进制表示法中的低10位。

此外,向右移动20会在最后丢弃所有20位,而只保留上面的12位吗?

我想用十六进制表示法打印X的低10位;由于十六进制中的每个字符都是4位,FF=8位,那么&用0x2FF获得十六进制表示法中的低10位。

不,那是不正确的。您可能希望使用0x3FF来获得低10位。(二进制中的0x2FF为:1011111111(。如果你对十六进制值有点不确定,那么现在更简单的方法是通过二进制常量,例如

// mask lowest ten bits in hex
int output1 = X & 0x3FF;

// mask lowest ten bits in binary
int output1 = X & 0b1111111111;

此外,向右移动20会在末尾丢弃所有20位,并只保留上面的12位吗?

LEFT移位的情况下,将从右侧移入零,并丢弃较高的位。

RIGHT移位的情况下,它取决于要移位的数据类型的符号。

// unsigned right shift
unsigned U = 0x80000000;
U = U >> 20;
printf("%xn", U); // prints:  800
// signed right shift
int S = 0x80000000;
S = S >> 20;
printf("%xn", S); // prints:  fffff800

带符号右移通常将最高比特从左移入。无符号右移总是移到零。

顺便说一句:IIRC的C标准对有符号整数移位有点模糊。我相信,理论上有可能有一个硬件平台,可以为有符号右移(即微控制器(进行零移位。不过,您的大多数典型平台(Intel/Arm(都会在最高位发生变化。

假设为32位int,则会出现以下问题:

  • 0xcdba4321太大,无法放入int中。在这种特定的情况下,十六进制常量本身实际上是unsigned int,因为C中有一个奇数类型的规则。从那里你可以强制隐式转换为int,很可能以负数结束
  • Y >> 20右移负数,这是不可移植的行为。它可以移位为一(算术移位(,也可以移位为零(逻辑移位(,具体取决于编译器。而右移无符号类型是定义明确的,并且总是导致逻辑移位
  • & 0xFF屏蔽掉8位,而不是10位
  • %X需要unsigned int,而不是int

你所有问题的根源是"草率打字"-也就是说,当你真正需要一个更合适的类型时,到处写int。您应该从stdint.h开始使用可移植类型,在本例中为uint32_t。还要养成一个习惯,总是用uU后缀来结束十六进制常量。

一个固定程序:

#include <stdio.h>
#include <stdint.h>
int main (void)
{
uint32_t X = 0x1234ABCDu;
uint32_t Y = 0xcdba4321u;
printf("%Xn", X & 0x3FFu);
printf("%Xn", Y >> (32-12));
}

CCD_ 16掩模也可以被写为CCD_。

(严格地说,您需要使用inttypes.h中的说明符打印stdint.h类型,但不要同时引入这些说明符来混淆答案。(

这个问题有很多高价值的答案。

以下是更多可能引发好奇心的信息。。。

int main() {
uint32_t X;
X = 0x1234ABCDu; // your first hex number
printf( "%Xn", X );
X &= ((1u<<12)-1)<<20; // mask 12 bits, shifting mask left
printf( "%Xn", X );
X = 0x1234ABCDu; // your first hex number
X &= ~0u^(~0u>>12);
printf( "%Xn", X );
X = 0x0234ABCDu; // Note leading 0 printed in two styles
printf( "%X %08Xn", X, X );
return 0;
}
1234ABCD
12300000
12300000
234ABCD 0234ABCD

以十六进制表示法打印Y的高12位

  • 若要在int的宽度未知时处理此问题,请首先使用类似sizeof(unsigned)*CHAR_BIT的代码来确定宽度。(C指定它必须至少为16位。(

  • 最好使用CCD_ 20或用CCD_。

#include <limits.h>
int output2 = Y;
printf("%Xn", (unsigned) output2 >> (sizeof(unsigned)*CHAR_BIT - 12));
// or
printf("%Xn", (output2 >> (sizeof output2 * CHAR_BIT - 12)) & 0x3FFu);
  • 罕见的非2的补码编码的int需要额外的代码-未显示。

  • 非常罕见的填充int需要其他位宽检测-未显示。

最新更新