Чтобы замаскировать младшие offset
биты, ваши вычисления для mask
в порядке, а выражение - нет. Это должно быть:
byte = (byte & ~mask);
или просто:
byte &= ~mask;
Чтобы вычислить маску из смещения с помощью (1 << offset) - 1
, вы должны знать, что смещение должно быть меньше количества битов. в виде 1
. 1
является int
, если означает offset < 32
, поэтому вы не можете вычислить маску для 32-битного поля таким образом.
Более того, даже 31
представляет проблему, потому что (1 << 31)
превышает ассортимент типа int
. Чтобы избежать этого, вы должны написать (1U << offset) - 1
и сначала проверить, offset < 32
.
Лучшая альтернатива, которая работает для offset
значений от 1
до 32
, это:
unsigned mask = ~0U >> (sizeof(unsigned) * CHAR_BIT - offset);
bits &= ~mask;
или проще с противоположной маской:
bits &= ~0U << offset;
Вот макросы для получения, очистки и установки битового поля в unsigned int
:
#define GET_MASK(width) (~0U >> (sizeof(unsigned) * CHAR_BIT - (width)))
#define GET_FIELD(x, pos, width) (((x) >> (pos)) & GET_MASK(x, width))
#define CLEAR_FIELD(x, pos, width) (((x) &= ~(GET_MASK(x, width) << (pos)))
#define SET_FIELD(x, pos, width, val) ((x) = ((x) & ~(GET_MASK(x, width) << (pos))) | ((val) << (pos)))