需要帮助理解K&R C第2章中的“getbits()”方法

在第2章,关于按位运算符的部分(第2.9节),我无法理解其中一个示例方法是如何工作的。

这是提供的方法:

unsigned int getbits(unsigned int x, int p, int n) { return (x >> (p + 1 - n)) & ~(~0 << n); } 

这个想法是,对于给定的数字x ,它将返回从位置p开始的n位,从右边开始计数(最右边的位是位置0)。 给定以下main()方法:

 int main(void) { int x = 0xF994, p = 4, n = 3; int z = getbits(x, p, n); printf("getbits(%u (%x), %d, %d) = %u (%X)\n", x, x, p, n, z, z); return 0; } 

输出是:

getbits(63892 (f994), 4, 3) = 5 (5)

我得到了部分内容,但我对“大图片”有困难,主要是因为我不理解的比特(没有双关语)。

我特别遇到问题的部分是补充部分: ~(~0 << n) 。 我想我得到了第一部分,处理x ; 这是我正在努力的部分(然后是面具) – 以及如何将它们组合在一起以实际检索这些部分。 (我已经validation了它正在使用代码并使用calc.exe检查我的结果 – 感谢上帝它有一个二进制视图!)

有帮助吗?

我们的例子中使用16位。 在这种情况下,~0等于

 1111111111111111 

当我们左移这n位(在你的情况下为3)时,我们得到:

 1111111111111000 

因为左边的1秒被丢弃, 0秒被输入右边。 然后重新补充它给出:

 0000000000000111 

所以这只是一个聪明的方法,可以在数字的最不重要部分获得n 1位。

您描述的“x位”已将给定数字(f994)向右移动得足够远,以便最不重要的3位是您想要的位数。 在此示例中,您请求的位被“。”包围。 字符。

 ff94 11111111100.101.00 # original number >> p+1-n [2] 0011111111100.101. # shift desired bits to right & ~(~0 << n) [7] 0000000000000.101. # clear all the other (left) bits 

你有你的位。 塔达!!

我想说最好的办法是手工解决问题,这样你就会明白它是如何运作的。

这是我使用8位unsigned int所做的。

  1. 我们的数字是75,我们希望从位置6开始的4位。函数的调用将是getbits(75,6,4);

  2. 二进制75是0100 1011

  3. 因此,我们创建一个4位长的掩码,从最低位开始,这样做。

~0 = 1111 1111
<< 4 = 1111 0000
〜= 0000 1111

好的,我们拿到了面具。

  1. 现在,我们将我们想要的数字从数字中推出到最低位,因此我们将二进制75移位6 + 1-4 = 3。

0100 1011 >> 3 0000 1001

现在我们有一个低位正确位数的掩码和低位原始数字的所需位。

  1. 所以我们和他们
   0000 1001 
&0000 1111 ============ 0000 1001

所以答案是十进制9。

注意:高阶半字节恰好全部为零,在这种情况下使掩蔽冗余,但它可能是任何取决于我们开始的数字的值。

~(~0 << n)创建一个掩码,该n掩码将打开n个最右边的位。

 0 0000000000000000 ~0 1111111111111111 ~0 << 4 1111111111110000 ~(~0 << 4) 0000000000001111 

用其他东西对结果进行AND运算将返回n位中的内容。

编辑:我想指出这个程序员的计算器我一直在使用: AnalogX PCalc 。

还没有人提到它,但在ANSI C ~0 << n会导致未定义的行为。

这是因为~0是负数,左移负数是未定义的。

参考:C11 6.5.7 / 4(早期版本有类似的文字)

E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充。 [...]如果E1具有有符号类型和非负值,并且E1 × 2 E2可在结果类型中表示,那么这就是结果值; 否则,行为未定义。

在K&R C中,这段代码将依赖于K&R开发的特定类系统,在执行有符号数的左移时从左侧移动1位(此代码也依赖于2的补码表示),但其他一些系统不共享这些属性,因此C标准化过程未定义此行为。

所以这个例子真的只是一个有趣的历史好奇心,它不应该用于任何真实的代码自1989年(如果不是更早)。

使用示例:int x = 0xF994,p = 4,n = 3; int z = getbits(x,p,n);

并专注于这组操作〜(〜0 << n)

对于任何位集(10010011等),您希望生成一个“掩码”,仅拉出您想要查看的位。 所以10010011或0x03,我对xxxxx011感兴趣。 什么是提取该组的面具? 00000111现在我想要sizeof int独立,我会让机器完成工作,即从一个字节机器的0开始,对于一个字机器它是0x00,它是0x0000等等64位机器将代表64位或0x0000000000000000

现在应用“not”(〜0)并获得11111111
右移(<<)由n得到11111000
并且“不”那并获得00000111

所以10010011&00000111 = 00000011
你还记得布尔运算是如何工作的吗?

ANSI C ~0 >> n会导致未定义的行为

//关于左移的post导致问题是错误的。

unsigned char m,l;

m = ~0 >> 4; 产生255并且它等于~0但是,

m =〜0; l = m >> 4; 产生正确值15,如下:

m = 255 >> 4;

没有任何问题,左移负~0 <<无论如何