访问C中char的位

我有一个hex数0x37,它的二进制表示是0011 0111.如何访问二进制表示的前两位是“11”? 如何使用位移或屏蔽来实现此目的? 我可以一点一点地访问,但不能一次访问两位?

如果您&您的号码为0x03,您将获得最后两位。

 char c = 0x37; char mask = 0x03; char lastTwo = c & mask; 

这是一个一点一点地访问它的示例:

 #include  int main() { char byte = 0x37; int i; for(i = 7; 0 <= i; i --) printf("%d\n", (byte >> i) & 0x01); return 0; } 

您也可以使用位字段来执行此操作。 关于位字段的不好的部分是它们的工作原理在某种程度上依赖于编译器,但如果你不需要将代码移植到许多架构中,也许它很好。

这是一个例子,写在Ubuntu Linux计算机上并使用GCC进行测试。

 #include  #include  #pragma pack(1) typedef struct { unsigned int low2: 2; // 2 bits of the byte unsigned int high6: 6; // 6 more bits of the byte } MYBYTE; typedef union { MYBYTE mybyte; unsigned char b; } MYUNION; main() { MYUNION m; assert(sizeof(m) == 1); mb = 0x03; assert(m.mybyte.low2 == 0x03); assert(m.mybyte.high6 == 0x00); printf("low2 of 0x03 is: %u\n", m.mybyte.low2); printf("high6 of 0x03 is: %u\n", m.mybyte.high6); mb = 0xff; printf("low2 of 0x03 is: %u\n", m.mybyte.low2); printf("high6 of 0x03 is: %u\n", m.mybyte.high6); assert(m.mybyte.low2 == 0x03); assert(m.mybyte.high6 == 0x3f); m.mybyte.high6 = 0x1c; m.mybyte.low2 = 0x01; assert(mb == 0x71); printf("mb is: 0x%02x\n", mb); return 0; } 

联盟在那里,所以我们可以作为一个完整的字节访问它,或者通过位字段访问它。 #pragma pack(1)用于确保位字段打包为一个字节,其中没有额外的“填充”位。 (正如我之前所说,当您使用位字段时,您依赖于实现细节。)

但看看访问你想要的位是多么简单和干净。 您可以写入一个完整的字节并读出您想要的位,或者写入您想要的位并读出整个字节。

如果你打算使用这样的代码,那么有一些断言确保它正常工作总是一个好主意。

如果您不打算使用位字段,我建议您定义一个function,为您进行移位和屏蔽,以确保您不会陷入困境。 也许是这样的:

 #include  static unsigned int _bit_masks[] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, }; #define MIN(a, b) \ ((a) < (b) ? (a) : (b)) unsigned int bits(unsigned int x, unsigned int i_bit, unsigned int c_bits) { assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit assert(i_bit <= 31); if (i_bit > 31) return 0; c_bits = MIN(c_bits, 32 - i_bit); // shift-and-mask to grab the requested bits, and return those bits return (x >> i_bit) & _bit_masks[c_bits]; } 

传入一个值,然后传入你想要位的位,以及你想要多少位。 因此,要从位位置2开始获取6位,测试值为0x71,您可以调用:

 x = bits(0x71, 2, 6); // x is set to 0x1c 

如果您不喜欢查找表,并且希望最小的代码执行此操作,则可以使用:

 unsigned int bits(unsigned int x, unsigned int i_bit, unsigned int c_bits) { const unsigned int mask_bits = 0xffffffff; assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit assert(i_bit <= 31); if (i_bit > 31) return 0; c_bits = MIN(c_bits, 32 - i_bit); // shift-and-mask to grab the requested bits, and return those bits return (x >> i_bit) & (mask_bits >> (32 - c_bits)); } 

您需要确保声明掩码位是unsigned因为如果它们已经签名,则右移操作将进行符号扩展。

如果将该函数的最后一个版本声明为内联,将其放入头文件中,并使用i_bitc_bits常量值调用它,它将编译为最小代码以解决问题。 (例如,如果i_bit为0,编译器知道>> 0不执行任何操作,并且不会生成该代码。如果编译器将c_bits知道为常量,它可以完成在编译时移动mask_bits所有工作但是你需要确保使用的是一个版本的assert() ,它在你的发布版本中编译成任何东西,或者使用你自己的ASSERT()宏并使你的宏编译成一无所获。

你最好的选择就是使用比特屏蔽,就像你提到的那样。 像这样的东西应该做的伎俩:

 x = 0x37; y = x&0x30; //Mask out the first two bits of the higher nibble y = y>>4; 

这是最容易使用的function,我不希望别人在得到类似的东西之前长时间挣扎 –

 char get_bits(char a, char no_of_bits) { return a & ((no_of_bits << 1) - 1); } char a = 0x37; char b = get_bits(a, 2); 

希望它能帮助将来的某个人