На рассмотрении (после принятия), @ Eric Postpischil часть ответа о UCHAR_MAX
создает предпочтительную маску.
#define BYTE_MASK UCHAR_MAX
Значение UCHAR_MAX
должно равняться2 CHAR_BIT - 1. C11dr §5.2.4.2.1 2
Поскольку unsigned char
не может иметь заполнение.Таким образом, UCHAR_MAX
всегда является шаблоном набора всех битов в символьном типе и, следовательно, в «байте» C.
some_signed & some_unsigned
- проблема с дополнением, отличным от 2, поскольку some_signed
преобразовать в unsigned
до &
, изменив таким образом битовую комбинацию на отрицательных значениях.Чтобы избежать, маска «все единицы» должна быть подписана при маскировании подписанных типов.Обычно это случай с foo & UINT_MAX
Заключение
Предположим: foo
имеет некоторый целочисленный тип.
Если толькоДополнение 2 вызывает беспокойство, используйте приведение - оно не меняет битовую комбинацию.
unsigned char lsb = (unsigned char) foo;
В противном случае с любым целочисленным кодированием и CHAR_MAX <= INT_MAX
unsigned char lsb = foo & UCHAR_MAX;
В противном случае TBD
Смещение unsigned
1 на CHAR_BIT
с последующим вычитанием 1 будет работать даже в эзотерических системах, не являющихся дополнением к 2. @ Какой-то программист, чувак .Обязательно используйте unsigned math .
В таких системах это сохраняет битовый шаблон в отличие от (unsigned char)
, приведенного к отрицательным целым числам.
unsigned char mask = (1u << CHAR_BIT) - 1u;
unsigned char lsb = foo & mask;
Или сделать define
#define BYTE_MASK ((1u << CHAR_BIT) - 1u)
unsigned char lsb = foo & BYTE_MASK;
Чтобы также справиться с теми неприятными случаями, когда UINT_MAX == UCHAR_MAX
, где 1u << CHAR_BIT
будет UB, сдвиг в 2 шага.
#define BYTE_MASK (((1u << (CHAR_BIT - 1)) << 1u) - 1u)