Insert bit into uint16_t

泪湿孤枕 提交于 2021-02-11 06:18:59

问题


Is there any efficient algorithm that allows to insert bit bit to position index when working with uint16_t? I've tried reading bit-by-bit after index, storing all such bits into array of char, changing bit at index, increasing index, and then looping again, inserting bits from array, but could be there a better way? So I know how to get, set, unset or toggle specific bit, but I suppose there could be better algorithm than processing bit-by-bit.

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

P.S. The solution must be in pure ANSI-compatible C. I know that 0b prefix may be specific to gcc, but I've used it here to make things more obvious.


回答1:


Use bitwise operators:

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



回答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));
}

Bits are typically counted from the right, where the least significant bit (lsb) resides, to the left, where the most significant bit (msb) is located. I allowed for insertion from either side by creating two functions. The one expected, according to the question, is bit_insert_msb.

Both functions perform a sanity check, setting errno to ERANGE and returning 0 if the value of idx is too large. I also provided some of C99's _Bool behaviour for the bit parameter in the return statements: 0 is 0 and any other value is 1. If you use a C99 compiler, I'd recommend changing bit's type to _Bool. You can then replace (!!bit) with bit directly.

I'd love to say it could be optimised, but that could very well make it less comprehensible.

Happy coding!




回答3:


If you're counting bits from the left

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);

There may be many ways more efficient but this way it's easy to understand



来源:https://stackoverflow.com/questions/20785360/insert-bit-into-uint16-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!