如何在C中获取整数的特定位段?

时间:2015-04-30 04:58:10

标签: c bit-manipulation bit

给你一个getTemps()函数返回一个由以下各项组成的整数:每日高温 在位20-29中,位10-19中的每日低温,以及位0-9中的当前温度全部 作为2的补码10位整数。 编写一个C程序,提取高,低和当前温度并打印值。

我得到了这种情况。所以我的问题是如何获得整数的特定段。

到目前为止,我有:

#include <stdio.h>
unsigned createMask(unsigned a, unsigned b){
    unsigned r = 0;
    unsigned i;
    for (i=a; i<=b; i++){
        r |= 1 << i;

    }
    return r;
}
int main(int argc, char *argv[])
{
  unsigned r = createMask(29,31);
  int i = 23415;
  unsigned result = r & i;
  printf("%d\n", i);
  printf("%u\n", result);
}

例如,整数23415将具有二进制00000000 00000000 01011011 01110111

然后第29到31位应该是111或整数-1,因为它的2是补码。

3 个答案:

答案 0 :(得分:3)

位域中提取编码信息有三种基本方法。前两个是相关的,仅在位域结构的初始化方式上有所不同。第一个也是最简单的是简单地创建一个位域结构,定义与结构的每个成员相关联的位。对于用于创建位域的类型,位的总和不能超过sizeof type * CHAR_BIT位。一个简单的例子是:

#include <stdio.h>

typedef struct {
    unsigned cur  : 10,
             low  : 10,
             high : 10;
} temps;

int main (void) {

    unsigned n = 0;                 /* encoded number of temps  */

    n = 58;                         /* fill number (58, 46, 73) */
    n |= (46 << 10);
    n |= (73 << 20);

    temps t = *(temps *)&n;         /* initialize struct t      */

    /* output value and temps */
    printf ("\n number entered : %u\n\n", n);

    printf ("   %2hhu - %2hhu  value : %u (deg. F)\n", 0, 9, t.cur);    
    printf ("   %2hhu - %2hhu  value : %u (deg. F)\n", 10, 19, t.low);    
    printf ("   %2hhu - %2hhu  value : %u (deg. F)\n\n", 20, 29, t.high);    

    return 0;
}

注意: memcpy也可用于初始化结构的值,以避免转换n的地址。 (这是故意这样做的,以避免包含string.h)。

下一个方法涉及在表示的数据类型和上面讨论的完全相同的结构之间创建联合。使用union的好处是你可以避免使用类型转换,或者memcpy一个值来初始化struct。您只需将编码值分配给union中的数字类型即可。使用此方法的相同示例是:

#include <stdio.h>

typedef struct {
    unsigned cur  : 10,
             low  : 10,
             high : 10;
} temps;

typedef union {
    temps t;
    unsigned n;
} utemps;

int main (void) {

    unsigned n = 0;                 /* encoded number of temps  */

    n = 58;                         /* fill number (58, 46, 73) */
    n |= (46 << 10);
    n |= (73 << 20);

    utemps u;                       /* declare/initialize union */
    u.n = n;

    /* output value and temps */
    printf ("\n number entered : %u\n\n", n);

    printf ("   %2hhu - %2hhu  value : %u (deg. F)\n", 0, 9, u.t.cur);    
    printf ("   %2hhu - %2hhu  value : %u (deg. F)\n", 10, 19, u.t.low);    
    printf ("   %2hhu - %2hhu  value : %u (deg. F)\n\n", 20, 29, u.t.high);    

    return 0;
}

最后,第三种方法既不使用 struct 也不使用 union ,而只是依靠 bit shift 操作来实现相同的目的。一个简单的例子是:

#include <stdio.h>
#include <limits.h>     /* for CHAR_BIT */

int main (void) {

    unsigned n = 0;                 /* encoded number of temps  */
    unsigned char i = 0;            /* loop counter             */
    unsigned char r = 10;           /* number of bits in temps  */
    unsigned char s = 0;            /* shift accumulator        */
    unsigned v = 0;                 /* extracted value          */

    n = 58;                         /* fill number (58, 46, 73) */
    n |= (46 << 10);
    n |= (73 << 20);

    printf ("\n number entered : %u\n\n", n);

    /* extract and output temps from n */
    for (i = 0; i < (sizeof n * CHAR_BIT)/r; i++)
    {
        v = (n >> i * r) & 0x3ff;
        printf ("   %2hhu - %2hhu  value : %u (deg. F)\n", s, s + r - 1, v);
        s += r;
    }

    printf ("\n");

    return 0;
}

注意:您可以使用mask功能自动创建createMask。虽然更长,但换档方法不是计算密集型的,因为换档操作几乎不需要完成。虽然可以忽略不计,但乘法也可以替换为进一步调整性能的转换和补充。唯一昂贵的指令是设置循环测试子句的划分,但同样可以忽略不计,所有这些情况都可能由编译器优化。

以上所有示例都会产生完全相同的输出:

$ ./bin/bit_extract_shift

 number entered : 76593210

    0 -  9  value : 58 (deg. F)
   10 - 19  value : 46 (deg. F)
   20 - 29  value : 73 (deg. F)

答案 1 :(得分:1)

您可以使用unionbit field来执行此操作。尝试这样的事情:

struct TEM_BITS {
    unsigned int tem_high :10;
    unsigned int tem_low  :10;
    unsigned int tem_cur  :10;
};

union TEM_U {
    int tem_values;
    struct TEM_BITS bits;
}

TEM_U t;
t.tem_values = 12345;

printf("tem_high : 0x%X\n", t.bits.tem_high);
printf("tem_low  : 0x%X\n", t.bits.tem_low);
printf("tem_cur  : 0x%X\n", t.bits.tem_cur);

答案 2 :(得分:0)

我可能会倒退,但以下内容应该很接近。

int current=x&0x3ff;

int low = (x>>10)&0x3ff;

int high = (x>>20)&0x3ff;