如何获取C中整数的特定位段? [英] How to get specific bit segments of an integer in C?

查看:71
本文介绍了如何获取C中整数的特定位段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

You are given a getTemps() function returns an integer composed of: the daily high temperature in bits 20-29, the daily low temperature in bits 10-19, and the current temperature in bits 0-9, all as 2's complement 10-bit integers. Write a C program which extracts the high, low, and current temperature and prints the values.

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

I am given this situation. So my question is how do I get the specific segments of an integer.

到目前为止,我有:

#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

The integer 23415 for example would have the binary 00000000 00000000 01011011 01110111

那么第29位至第31位由于其2的补码,因此应为111或整数-1.

Then bits 29 through 31 for example should be 111 or integer -1 since its 2's complement.

推荐答案

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

There are three basic approaches for extracting encoded information from a bitfield. The first two are related and differ only in the manner the bitfield struct is initialized. The first and shortest is to simply create a bitfield struct defining the bits associated with each member of the struct. The sum of the bits cannot exceed sizeof type * CHAR_BIT bits for the type used to create the bitfield. A simple example is:

#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 ).

Note: memcpy can also be used to initialize the value for the structure to avoid casting the address of n. (that was done intentionally here to avoid inclusion of string.h).

下一个方法涉及在表示的数据类型和上面讨论的完全相同的结构之间创建 union .使用联合的好处是您不必强制转换或 memcpy 值来初始化结构.您只需将编码值分配给并集内的数字类型.使用此方法的相同示例是:

The next method involves creation of a union between the data type represented and the exact same struct discussed above. The benefit of using the union is that you avoid having to typecast, or memcpy a value to initialize the struct. You simply assign the encoded value to the numeric type within the union. The same example using this method is:

#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 操作来实现相同的目的.一个简单的例子是:

Finally, the third method uses neither a struct or union and simply relies on bit shift operations to accomplish the same purpose. A quick example is:

#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;
}

注意:您可以使用 createMask 函数自动创建 mask .移位方法虽然时间较长,但由于移位操作几乎不需要完成,因此计算量并不大.尽管微不足道,但乘法也可以通过移位和其他调整性能来代替.唯一昂贵的指令是设置循环测试子句的划分,但又可以忽略不计,所有这些情况都有可能由编译器进行优化.

Note: you can automate the creation of the mask with the createMask function. While longer, the shift method is not computationally intensive as shift operations take little to accomplish. While negligible, the multiplication could also be replaced with a shift and addition to further tweak performance. The only costly instruction is the division to set the loop test clause, but again it is negligible and all of these cases are likely to be optimized by the compiler.

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

All of the examples above produce exactly the same output:

$ ./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)

这篇关于如何获取C中整数的特定位段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆