Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 从无符号整数中提取位的函数_C_Bit Manipulation_Bit_Bit Shift - Fatal编程技术网

C 从无符号整数中提取位的函数

C 从无符号整数中提取位的函数,c,bit-manipulation,bit,bit-shift,C,Bit Manipulation,Bit,Bit Shift,编写一个名为bitpat\u get()的函数来提取指定的位集。让它接受三个参数:第一个参数是无符号整数,第二个参数是整数起始位数,第三个参数是位计数。使用比特编号从最左边的比特开始的约定,从第一个参数中提取指定数目的比特并返回结果。所以电话 bitpat\u-get(x,0,3) 从中提取最左边的三位。电话 bitpat_-get(x,3,5) 从左侧第四位开始提取五位 我真的不知道作者所说的提取比特是什么意思,所以我几乎可以肯定我的代码是错误的,它返回的任何东西都不是预期的返回值。不过,我还

编写一个名为
bitpat\u get()
的函数来提取指定的位集。让它接受三个参数:第一个参数是无符号整数,第二个参数是整数起始位数,第三个参数是位计数。使用比特编号从最左边的比特开始的约定,从第一个参数中提取指定数目的比特并返回结果。所以电话

bitpat\u-get(x,0,3)

从中提取最左边的三位。电话

bitpat_-get(x,3,5)

从左侧第四位开始提取五位

我真的不知道作者所说的提取比特是什么意思,所以我几乎可以肯定我的代码是错误的,它返回的任何东西都不是预期的返回值。不过,我还是会发布它:

#include <stdio.h>

unsigned int bitpat_get(unsigned int from, int start, int n);

int main(void)
{
    unsigned int x = 0xe1f4;

    printf("%x\n", bitpat_get(x, 0, 3));
    printf("%x\n", bitpat_get(x, 3, 5));
}

unsigned int bitpat_get(unsigned int from, int start, int n)
{
    unsigned int result = from;
    int bits;

    for (bits = 0; (from >> bits) != 0; ++bits)
        continue;

    unsigned int mask = (((1U << n) - 1) << (bits - n - start));

    result = from ^ mask;

    return result;
}
我真的不知道作者所说的提取比特是什么意思

让我们先解决这个问题。假设您有一个16位无符号整数,则位位置为:

                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
unsigned testVal = ~0U; // all one bits
for (bits = 0; testVal != 0; ++bits, testVal = testVal >> 1)
    ;
因此表达式
bitpat\u get(x,0,3)
应该给出从偏移量0开始的三位,或者
abc
。类似地,
bitpat\u get(x,3,5)
会给出偏移量3处的五位,或者
defgh

这应该足以理解你需要做什么


就你需要做什么来实现这一点而言,这是一个两步操作。第一种方法是实际地将位右移(a),以便您需要的位位于最右边的位置。这取决于三条信息:

  • 无符号整数的位宽度
  • 要提取的偏移量;及
  • 要提取的位数
移位距离为
位宽-偏移-位需要
。对于第一种情况,这将是
16-0-3=13
,您可以看到将位右移13会将所需位放在最右边的部分:

                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|0|0|a|b|c|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
对于第二种情况,通过
16-3-5=8向右移可获得:

                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|a|b|c|d|e|f|g|h|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
第二步是掩盖左边你实际上不需要的部分。我们先做第二种情况,因为这有实际效果

掩码基本上是一系列位于右侧的一位,并且可以通过从零开始,然后针对您需要的每个位位置左移一位来获得。对于需要五位的情况,序列将是二进制的
0
1
11
111
1111
11111
。按位并将其与值相加将得到:

                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|a|b|c|d|e|f|g|h| <- value
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|1|1|1|1|1| <- "and" with
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|d|e|f|g|h| <- gives
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|1|0|1|0|1| <- value (21)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|1|1|1|1|1| <- "xor" with
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|0|1|0|1|0| <- `01010` (10): NOT the correct `10101`
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

就您发布的代码而言,我发现了一些问题

首先,我认为您的
for..continue
部分是为了根据您以后使用的值,找出
无符号int
的位宽度。但是,您根据传入的值计算它,这是不正确的。您应该基于位模式,其中最左边的位是1

换言之,如果传入的值为三(二进制
11
),请考虑当前循环将做什么-位宽度将计算为二,因为仅在两次移位后,将得到零值。因此,更好的方法是:

                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
unsigned testVal = ~0U; // all one bits
for (bits = 0; testVal != 0; ++bits, testVal = testVal >> 1)
    ;
其次是你的面具计算。您的代码被设置为就地提取位,这意味着您只需将其周围的所有其他位设置为零。最好将它们移到右侧进行提取(a)

第三,您应该知道,
^
是异或操作,如果您使用所有一个位的掩码,它将反转位,而不是按原样提取位。您要找的操作员是
&

举例来说,将异或运算符与
bitpat_get(21,11,5)
一起使用,将给出:

                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|a|b|c|d|e|f|g|h| <- value
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|1|1|1|1|1| <- "and" with
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|d|e|f|g|h| <- gives
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     1 1 1 1 1 1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|1|0|1|0|1| <- value (21)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|1|1|1|1|1| <- "xor" with
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|0|0|0|1|0|1|0| <- `01010` (10): NOT the correct `10101`
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

(a) 这是基于经验。你可能想让它们就位,但在我漫长且(偶尔)辉煌的职业生涯中,我总是发现让它们在移位部分更有用。例如,如果位11-13是某种类型的整数值,将它们移动到最右边的位实际上会给出值
0..7
,而不是集合
{0,4,8,…,28}
中的值


事实可能并非如此,因此,如果您只是注释掉另一种情况,我提供的代码将涵盖这两种情况。

您编写的代码当然很重要。@davernator没错,它帮助我更好地理解位操作,尽管我发现我得到的结果是错误的。非常好@Areg。另外,根据我的经验,一个好的基准测试(具有已知结果的实例)可以帮助您调试代码。如果您的代码在一组已知数据上产生正确的结果,那么代码正确的概率将大大增加。@davernator当然。然而,由于我不确定作者提取一组指定位的意思,所以我不确定什么是好的基准测试。这可能会发生,不是@Areg(:-)吗。如果你有作者的联系方式,也许你可以给他/她发电子邮件。与谷歌相关的一个好方法可能是了解shift操作符>,以及它们如何在具有little-endian和big-endian体系结构的系统上运行。非常中肯,但根据你想潜水的深度,可能会有过度的杀伤力。(:-)通常对位进行编号,以便位0是最低有效位,而不是最高有效位。这使事情变得更简单,因为您不需要知道无符号的大小——只需按所需的位位置进行右移,函数就变成了
return(from>>start)&((1U Ok…所以我理解了您编写的所有内容(这是绝对有意义的)并相应地更改了我的程序。但是,我同时运行了我的程序和你的程序,两种情况下的输出都是0。为什么会是这样?我无法理解它…@chrisdsodd那么,作者提到了位编号开始时的约定