Когда вопрос экономии памяти становится очень существенным, то может оказаться необходимым помещать в одно машинное слово несколько различных объектов; одно из особенно распространенных употреблений - набор однобитовых признаков в применениях, подобных символьным таблицам компилятора. Внешне обусловленные форматы данных, такие как интерфейсы аппаратных средств также зачастую предполагают возможность получения слова по частям.
Представьте себе фрагмент компилятора, который работает с символьной таблицей. С каждым идентификатором программы связана определенная информация, например, является он или нет ключевым словом, является ли он или нет внешним и/или статическим и т.д. Самый компактный способ закодировать такую информацию - поместить набор однобитовых признаков в отдельную переменную типа char или int.
Обычный способ, которым это делается, состоит в определении набора "масок", отвечающих соответствующим битовым позициям, как в
#define keyword 01 #define external 02 #define static 04
(числа должны быть степенями двойки). Тогда обработка битов сведется к "жонглированию битами" с помощью операций сдвига, маскирования и дополнения, описанных нами в лекции №2.
Некоторые часто встречающиеся идиомы:
flags |= external | static;
включает биты external и static в flags, в то время как
flags &= \^(еxternal | static);
их выключает, а
if ((flags & (external | static)) == 0) ...
истинно, если оба бита выключены.
Хотя этими идиомами легко овладеть, язык "C" в качестве альтернативы предлагает возможность определения и обработки полей внутри слова непосредственно, а не посредством побитовых логических операций. Поле - это набор смежных битов внутри одной переменной типа int. Синтаксис определения и обработки полей основывается на структурах. Например, символьную таблицу конструкций #define, приведенную выше, можно бы было заменить определением трех полей:
struct { unsigned is_keyword : 1; unsigned is_extern : 1; unsigned is_static : 1; } flags;