给定值存储到整数中指定位

《C和指针》5.9 - 5 :

编写函数,把一个给定的值存储到一个整数中指定的几个位。它的原型如下:

int store_bit_field(int original_value, 
        int value_to_store,
        unsigned starting_bit,
        unsigned ending_bit);

假定整数中的位是从右向左进行编号。因此,起始位的位置不会小于结束位的位置,为了更清楚的说明,函数应该返回下列值。

原始值需要储存的位起始位结束位返回值
0x00x1440x10
0xffff0x1231540x123f
0xffff0x1231390xc7ff

提示:把一个值存储到一个整数中指定的几个位分为5个步骤,以上表最后一行为例:

1).创建一个掩码,它是一个值,其中需要存储的位置相对应的那几个位设置为1,此时掩码

00111110,00000000

2).用掩码的反码对原值执行AND操作,将那几个位设置为0.原值1111111111111111,操作后变为

11000001,11111111

3).将新值左移,使它与需要存储的位对齐,新值00000001,00100011(0x123),左移后变为

新值存储在第9-13位,将其每一位左移,直到最低位左移到第9位,保持最低位对齐。

01000110,00000000

4).把移位后的值与掩码进行位AND操作,确保除那几个需要存储的位之外的其余位都设置为0,进行这个操作之后,值变为

00000110,00000000

5).把结果值与原值进行位OR操作,结果为(0xc7ff)

11000111,11111111

在所有任务中,最困难的是创建掩码,你一开始可以把~0这个值强制转换为无符号值,然后再对它进行移位。

根据上面的步骤,可以实现如下代码:

#include <stdio.h>
#include <stdint.h>


/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i)    \
    (((i) & 0x80ll) ? '1' : '0'), \
    (((i) & 0x40ll) ? '1' : '0'), \
    (((i) & 0x20ll) ? '1' : '0'), \
    (((i) & 0x10ll) ? '1' : '0'), \
    (((i) & 0x08ll) ? '1' : '0'), \
    (((i) & 0x04ll) ? '1' : '0'), \
    (((i) & 0x02ll) ? '1' : '0'), \
    (((i) & 0x01ll) ? '1' : '0')

#define PRINTF_BINARY_PATTERN_INT16 \
    PRINTF_BINARY_PATTERN_INT8              PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
    PRINTF_BYTE_TO_BINARY_INT8((i) >> 8),   PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
    PRINTF_BINARY_PATTERN_INT16             PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
    PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64    \
    PRINTF_BINARY_PATTERN_INT32             PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
    PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */


void print_binary(unsigned int number) {
    printf(PRINTF_BINARY_PATTERN_INT32, PRINTF_BYTE_TO_BINARY_INT32(number));
}



int store_bit_field(int original_value,
                    int value_to_store,
                    unsigned starting_bit,
                    unsigned ending_bit) {

    printf("\n\norigin: 0x%0x\n", original_value);
    //取得掩码
    unsigned mask = 0;
    for (int i = starting_bit; i <= ending_bit; i++) {
        mask |= (1 << i);
    }
    printf("Mask:");
    print_binary(mask);
    printf("\n");

    //将目标位置清0
    printf("Original value (clear dst bits): ");
    unsigned tmp = original_value & ~mask;
    print_binary(tmp);

    printf("\nNew value (low bits align):");
    //将要储存的新值和目标位置对其,低位对齐
    value_to_store = value_to_store << starting_bit;
    print_binary(value_to_store);

    printf("\nNew value (get dst bits with mask):");
    //通过掩码取得对齐后的新值
    value_to_store &= mask;
    print_binary(value_to_store);

    printf("\nResult:");
    //对齐后的值与原值清除目标位后的值或操作
    unsigned result = value_to_store | tmp;
    print_binary(mask);

    printf("\nresult: 0x%0x\n", result);
    print_binary(result);

}

int main () {
    store_bit_field(0x0, 0x1, 4, 4);

    store_bit_field(0xffff, 0x123, 4, 15);

    store_bit_field(0xffff, 0x123, 9, 13);

    return 0;
}

输出:



origin: 0x0
Mask:00000000000000000000000000010000
Original value (clear dst bits): 00000000000000000000000000000000
New value (low bits align):00000000000000000000000000010000
New value (get dst bits with mask):00000000000000000000000000010000
Result:00000000000000000000000000010000
result: 0x10
00000000000000000000000000010000

origin: 0xffff
Mask:00000000000000001111111111110000
Original value (clear dst bits): 00000000000000000000000000001111
New value (low bits align):00000000000000000001001000110000
New value (get dst bits with mask):00000000000000000001001000110000
Result:00000000000000001111111111110000
result: 0x123f
00000000000000000001001000111111

origin: 0xffff
Mask:00000000000000000011111000000000
Original value (clear dst bits): 00000000000000001100000111111111
New value (low bits align):00000000000000100100011000000000
New value (get dst bits with mask):00000000000000000000011000000000
Result:00000000000000000011111000000000
result: 0xc7ff
00000000000000001100011111111111

这个问题可以很好的帮助我们理解数据的二进制存储结构和位运算,书上给出了步骤,如果没有给这个算法步骤,我们也需要能够想到:

1、得到目标位置的掩码。

2、根据掩码取反再与原值相与,清空目标位置的数据。

3、新的值要存入目标位,但由于目标位的长度不确定,这里只能低位对齐,保证尽可能存入低位,所以需要左移到需要对齐的位置,这里我直接将编号和大小调整为一致了,也可以根据题目将starting_bit和ending_bit交换。

4、利用掩码取出新值的目标位置区间的值。

5、将4的结果与2的结果进行或运算即可得到最终的值。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值