【问题标题】:Insert bit into uint16_t将位插入 uint16_t
【发布时间】:2013-12-26 13:02:32
【问题描述】:

在使用uint16_t 时,是否有任何有效的算法允许将位bit 插入到index 的位置?我试过在index之后逐位读取,将所有这些位存储到char的数组中,在index处更改位,增加index,然后再次循环,从数组中插入位,但可以有更好的方法吗?所以我知道如何获取、设置、取消设置或切换特定位,但我想可能有比逐位处理更好的算法。

uint16_t bit_insert(uint16_t word, int bit, int index);
bit_insert(0b0000111111111110, 1, 1); /* must return 0b0100011111111111 */

附:解决方案必须是纯 ANSI 兼容的 C。我知道 0b 前缀可能特定于 gcc,但我在这里使用它是为了让事情更明显。

【问题讨论】:

  • 为什么需要循环?只需同时移动所有相邻的位。你在这里的“插入”是什么意思,你从哪里计算位?在您的代码中,您在索引 0 处插入一个 0 位,但我在左侧和右侧的结果中只看到新的“1”位
  • 过失;这里应该是 1 作为第二个参数,而不是零。

标签: c bit-manipulation bit bit-shift


【解决方案1】:

使用位运算符:

#define BIT_INSERT(word, bit, index)  \
    (((word) & (~(1U << (index)))) | ((bit) << (index)))

【讨论】:

  • 他的意思是“插入”,即将剩余的位向左移动,不将bit分配给index处的位,他从MSB开始计算位
  • @LưuVĩnhPhúc 他的问题不清楚,因为不清楚提供的示例,所以我将其视为:在位位置 index 计算具有 bit 值的值,其他位设置为那些word.
【解决方案2】:
#include <errno.h>
#include <stdint.h>

/* Insert a bit `idx' positions from the right (lsb). */
uint16_t
bit_insert_lsb(uint16_t n, int bit, int idx)
{
    uint16_t lower;

    if (idx > 15) {
        errno = ERANGE;
        return 0U;
    }

    /* Get bits 0 to `idx' inclusive. */
    lower = n & ((1U << (idx + 1)) - 1);

    return ((n & ~lower) | ((!!bit) << idx) | (lower >> 1));
}

/* Insert a bit `idx' positions from the left (msb). */
uint16_t
bit_insert_msb(uint16_t n, int bit, int idx)
{
    uint16_t lower;

    if (idx > 15) {
        errno = ERANGE;
        return 0U;
    }

    /* Get bits 0 to `16 - idx' inclusive. */
    lower = n & ((1U << (15 - idx + 1)) - 1);

    return ((n & ~lower) | ((!!bit) << (15 - idx)) | (lower >> 1));
}

通常从最低有效位 (lsb) 所在的右侧到最高有效位 (msb) 所在的左侧计算位。我允许通过创建两个函数从任一侧插入。根据问题,预期是bit_insert_msb

两个函数都执行完整性检查,将errno 设置为ERANGE,如果idx 的值太大则返回0。我还在return 语句中为bit 参数提供了一些C99 的_Bool 行为:0 为0,任何其他值为1。如果您使用C99 编译器,我建议更改bit键入_Bool。然后,您可以直接将(!!bit) 替换为bit

我很想说它可以优化,但这很可能会降低它的可理解性。

编码愉快!

【讨论】:

    【解决方案3】:

    如果你从左边数位

    mask = (1 << (16 - index + 1)) - 1;  // all 1s from bit "index" to LSB
    // MSB of word (from left to index) | insert bit at index | LSB of word from (index-1)
    word = (word & ~mask) | (bit << (16 - index)) | ((word & mask) >> 1);
    

    可能有很多更有效的方法,但这种方法很容易理解

    【讨论】:

    • 用 0x8ffe 代替示例 0x0ffe 试试这个。这不起作用,因为当您使用 ~ 运算符时,您不小心打开了掩码中的符号位,这将关闭结果中的符号位。
    • @ChronoKitsune 输入错误,我认为是“-1”,而不是“~”
    猜你喜欢
    • 2023-03-09
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    • 1970-01-01
    相关资源
    最近更新 更多