问题
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