Существует ли общая битовая маска «изолировать один байт» для всех систем, независимо от CHAR_BIT? - PullRequest
0 голосов
/ 24 января 2019

Если CHAR_BIT == 8 в вашей целевой системе (в большинстве случаев), очень легко замаскировать один байт:

unsigned char lsb = foo & 0xFF;

Однако, есть несколько систем и реализаций C, где CHAR_BIT не является ни 8, ни кратным.Поскольку стандарт C предписывает только диапазон минимум для значений char, нет гарантии, что маскирование с помощью 0xFF выделит для вас целый байт.

Я искал вокругпытаюсь найти информацию об общей «байтовой маске», но пока ничего не нашел.

Всегда есть решение O (n):

unsigned char mask = 1;
size_t i;
for (i = 0; i < CHAR_BIT; i++)
{
    mask |= (mask << i);
}

Однако мне интересно, есть ли где-нибудь макрос или строка кода O (1), которые могут это сделать,учитывая, насколько важна эта задача во многих сценариях программирования на системном уровне.

Ответы [ 3 ]

0 голосов
/ 24 января 2019

На рассмотрении (после принятия), @ 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)

0 голосов
/ 24 января 2019

UCHAR_MAX не обязательно должно быть равно (1U << CHAR_BIT) - 1U

вам нужно на самом деле и с этим рассчитанным значением не с UCHAR_MAX

value & ((1U << CHAR_BIT) - 1U).

Многие реальные реализации (например, TI) определяют UCHAR_MAX как 255 и испускают код, который ведет себя как код на машинах, имеющих 8-битные байты. Это сделано для сохранения совместимости с кодом, написанным для других целей.

Например

unsigned char x;

x++;

сгенерирует код, который проверяет, что значение x больше, чем UCHAR_MAX, и, если это правда, обнуляет 'x'

enter image description here

0 голосов
/ 24 января 2019

Самый простой способ извлечь unsigned char из целочисленного значения - просто привести его к unsigned char:

(unsigned char) SomeInteger

В соответствии с C 2018 6.3.1.3 2, в результате получается остаток от SomeInteger по модулю UCHAR_MAX+1. (Это неотрицательный остаток; он всегда настраивается так, чтобы он был больше или равен нулю и меньше UCHAR_MAX+1.)

Присвоение unsigned char имеет тот же эффект, так как присваивание выполняет преобразование (и инициализация тоже):

unsigned char x;
…
x = SomeInteger;

Если вам нужна явная битовая маска, UCHAR_MAX такая маска. Это так, потому что целые числа без знака являются чистыми двоичными числами в C, а максимальное значение целого числа без знака имеет все установленные биты значений. (Целые числа без знака в общем случае также могут иметь бит дополнения, но unsigned char может не иметь.)

В очень старых или эзотерических системах может возникнуть одно различие: если целое число со знаком представляется со знаком и величиной или дополнением вместо дополнения сегодняшних вездесущих двух, то результаты извлечения unsigned char из отрицательного значения будут различаются в зависимости от того, используете ли вы метод преобразования или метод битовой маски.

...