【问题标题】:Extract certain bits from A and replace only those extracted bits in B at a certain position从 A 中提取某些位并仅替换 B 中某个位置的那些提取位
【发布时间】:2021-01-06 01:55:43
【问题描述】:

提取和修改位
从打包的 final_value 中的一个位置选择 n 个位并写入任意位置,而不修改 uint16_t test_bit = 0x3048 的原始内容。 预期输出 = 0x5048
例如: 从 final_val 中选取 010(3bits from position 17) 并写入任意位置(位置 11 )
0x3048 = 0111 0000 0100 1000;
0x5048 = 0101 0000 0100 1000

几个例子:
例子 A:
粗体是提取的。我们从 Val_1 中提取位 0 到 7,并仅替换 Val_2 中的位 0 到 7,使位 8 到 15 保持不变。
Val_1 0x1b7 0000 0001 1011 0111
Val_2 0x27b7 0010 0111 1011 0111

示例 B:
从 Val1[从位 8 到 10] 中提取 3 位,并将其替换为 Val_2[从 11 到 13]。
Val_1 0x129 0000 0001 0010 1001
Val_2 0x4C48 0100 1100 0100 1000
到目前为止尝试过:

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

void read_and_write(uint32_t* final_val, uint16_t* write_val, uint8_t start_pos, uint8_t end_pos)
{
    uint32_t temp = *final_val;
    *write_val = (uint16_t) ((temp >> start_pos) & ((1 << end_pos) - 1)); // store the desired number of bits in write_val
    *final_val = (temp >> end_pos); //shift final_val by end_pos since those bits are already written
    printf("\n temp %x, write_val %x, final_val %x ", temp, *write_val, *final_val);
    
}

void main() 
{
    uint32_t final_val = 0x0; //Stores 20 extracted bits from val1, val2 and val3 into final_val (LSB to MSB in order)
    uint16_t ext_val1 = 0x80;
    uint8_t ext_val2 = 0x0; 
    uint8_t ext_val3 = 0x2;
    final_val = (ext_val1 | (ext_val2 << 9) | (ext_val3 << 17));
    printf ("\n final_val %x", final_val);
    
    uint16_t data_1, data_2, data_3, write_val1, write_val2, write_val3;
    // Read first 9 bits of final_val and write only into [0:9] position of existing data_1
    uint8_t start_pos = 0;
    uint8_t end_pos = 9;
    data_1 = 0x80;
    read_and_write(&final_val, &write_val1, start_pos, end_pos);
    write_val1 = write_val1 | data_1;
    
    // Read next 8 bits of final_val and write only into [0:8] position of existing data_2
    start_pos = 0;
    end_pos = 8;
    data_2 = 0x27b7;
    read_and_write(&final_val, &write_val2, start_pos, end_pos);
    write_val2 = write_val2 | data_2;
    
    //Read next 3 bits of final_val and write only into[13:11] position of existing  data_3
    start_pos = 11;
    end_pos = 13;
    data_3 = 0x3048;
    read_and_write(&final_val, &write_val3, start_pos, end_pos);
    write_val3 = write_val3 | data_3;
    printf ("\n val1 0x%x val2 0x%x val3 0x%x final_val 0x%x", write_val1, write_val2, ext_val3, final_val);
}

有人可以帮忙吗?使用旧方法忽略陈旧的代码。

【问题讨论】:

  • 到目前为止你做了什么?
  • @P__J__ 更新了我上面的代码。
  • 非有效位总是保证为0?也许您需要将它们过滤掉:(ext_val1 &amp; 0x1ff)(ext_val2 &amp; 0xff)(ext_val3 &amp; 0x7)
  • 示例中的位数不一致:示例A中的16位值中没有位置17,示例B中的3位是从位置8到10提取的,而不是从5到7.

标签: c bit-manipulation operators bitwise-operators bit


【解决方案1】:

这是一个带有辅助函数和测试框架的简单实现:

  • ((uint32_t)1 &lt;&lt; n) - 1 计算设置了低位 n 的二进制数 2n-1。
  • uint32_t mask = (((uint32_t)1 &lt;&lt; n) - 1) &lt;&lt; pos2; 计算 mask 并设置从位置 pos2 开始的 n 位。
  • (val2 &amp; ~mask) 清除 val2pos2 位置处的 n 位,而其他位保持不变。
  • extract(val1, pos1, n) &lt;&lt; pos2 将从val1 中提取的n 位移动到pos2 的位置,其他位为0
  • or-ing 这些值计算预期结果,从val1 复制的n 位从val2 中的pos2 位置开始。

代码如下:

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

uint32_t extract(uint32_t data, int pos, int n) {
    return (data >> pos) & (((uint32_t)1 << n) - 1);
}

uint32_t replace(uint32_t val1, uint32_t val2, int pos1, int n, int pos2) {
    uint32_t mask = (((uint32_t)1 << n) - 1) << pos2;
    return (val2 & ~mask) | (extract(val1, pos1, n) << pos2);
}

void test(uint32_t val1, uint32_t val2, int pos1, int n, int pos2) {
    uint32_t res = replace(val1, val2, pos1, n, pos2);
    printf("extracting bits [%d-%d] from 0x%04X to bits [%d-%d] in 0x%04X -> 0x%04X\n",
           pos1, pos1 + n - 1, val1, pos2, pos2 + n - 1, val2, res);
}

int main() {
    test(0x1234, 0x7048, 1, 3, 11);
    test(0x01b7, 0x2743, 0, 8, 0);
    test(0x0129, 0x7448, 8, 3, 11);
    return 0;
}

输出:

extracting bits [1-3] from 0x1234 to bits [11-13] in 0x7048 -> 0x5048
extracting bits [0-7] from 0x01B7 to bits [0-7] in 0x2743 -> 0x27B7
extracting bits [8-10] from 0x0129 to bits [11-13] in 0x7448 -> 0x4C48

【讨论】:

  • 感谢 Chqrlie。你能解释一下替换功能吗?
  • @c_prog_90:我用额外的细节更新了答案。
【解决方案2】:

这里有一些函数可以提取特定位的值并将它们替换为从另一个值中提取的值。

uint32_t extract(uint32_t read_data, int n_bits, int pos) 
{ 
    uint32_t mask = (n_bits < (CHAR_BIT * sizeof(mask) - 1)) ? ((1LU << n_bits) - 1) << pos  : -1; 


    return (mask & read_data) >> pos;
} 

uint32_t replace(uint32_t read_val, uint32_t write_val, int read_pos, int write_pos, int n_bits)
{
    uint32_t extracted = extract(read_val, n_bits, read_pos);
    uint32_t mask = (n_bits < (CHAR_BIT * sizeof(mask) - 1)) ? ((1LU << n_bits) - 1) << write_pos  : -1; 
    write_val &= ~mask;
    write_val |= extracted << write_pos;

    return write_val;
}


int main (void)
{
    uint32_t val = 0x1234;
    uint32_t val2 = 0xabcd;

    printf("%x\n", extract(val, 4, 8));
    printf("%x\n", replace(val, val2, 4, 8, 4));
}

【讨论】:

  • 感谢您的回答。 extract 有效,但从 replace 返回的值不正确。
  • @c_prog_90 是正确的:在这个例子中,它从 0x1234 开始从第 4 位(wfich 为 3)取 4 位,并替换从第 8 位开始的 0xabcs 4 位,给我们 0xa3cd 100% 正确跨度>
  • @c_prog_90 给我一个错误结果的例子
  • 我将所有内容都更改为 uint16_t。不确定这是否是导致问题的原因。另外,如果您能解释替换功能,请不胜感激。非常感谢您的回复。就我而言,我将提取值和替换值都存储为 unit16_t。对不起,我没有给出这个要求。
  • 我在问题中提供了示例 A 和 B。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
  • 1970-01-01
  • 2020-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多