6.7. Поля.
Когда вопрос экономии памяти становится очень существен-
ным, то может оказаться необходимым помещать в одно машинное
слово несколько различных объектов; одно из особенно расп-
росраненных употреблений - набор однобитовых признаков в
применениях, подобных символьным таблицам компилятора. внеш-
не обусловленные форматы данных, такие как интерфейсы аппа-
ратных средств также зачастую предполагают возможность полу-
чения слова по частям.
Представьте себе фрагмент компилятора, который работает
с символьной таблицей. С каждым идентификатором программы
связана определенная информация, например, является он или
нет ключевым словом, является ли он или нет внешним и/или
статическим и т.д. Самый компактный способ закодировать та-
кую информацию - поместить набор однобитовых признаков в от-
дельную переменную типа CHAR или INT.
Обычный способ, которым это делается, состоит в опреде-
лении набора “масок”, отвечающих соответствущим битовым по-
зициям, как в
#DEFINE KEYWORD 01
#DEFINE EXTERNAL 02
#DEFINE STATIC 04
(числа должны быть степенями двойки). Тогда обработка битов
сведется к “жонглированию битами” с помощью операций сдвига,
маскирования и дополнения, описанных нами в главе 2.
Некоторые часто встречающиеся идиомы:
FLAGS \!= EXTERNAL \! STATIC;
включает биты EXTERNAL и STATIC в FLAGS, в то время как
FLAGS &= \^(еXTERNAL \! STATIC);
·
146 -
их выключает, а
IF ((FLAGS & (EXTERNAL \! STATIC)) == 0) ...
истинно, если оба бита выключены.
Хотя этими идиомами легко овладеть, язык “C” в качестве
альтернативы предлагает возможность определения и обработки
полей внутри слова непосредственно, а не посредством побито-
вых логических операций. Поле - это набор смежных битов
внутри одной переменной типа INT. Синтаксис определения и
обработки полей основывается на структурах. Например, сим-
вольную таблицу конструкций #DEFINE, приведенную выше, можно
бы было заменить определением трех полей:
STRUCT \(
UNSIGNED IS_KEYWORD : 1;
UNSIGNED IS_EXTERN : 1;
UNSIGNED IS_STATIC : 1;
\) FLAGS;
Здесь определяется переменная с именем FLAGS, которая содер-
жит три 1-битовых поля. Следующее за двоеточием число задает
ширину поля в битах. Поля описаны как UNSIGNED, чтобы под-
черкнуть, что они действительно будут величинами без знака.
На отдельные поля можно ссылаться, как FLAGS.IS_STATIE,
FLAGS. IS_EXTERN, FLAGS.IS_KEYWORD И т.д., то есть точно так
же, как на другие члены структуры. Поля ведут себя подобно
небольшим целым без знака и могут участвовать в арифметичес-
ких выражениях точно так же, как и другие целые. Таким обра-
зом, предыдущие примеры более естественно переписать так:
FLAGS.IS_EXTERN = FLAGS.IS_STATIC = 1;
для включения битов;
FLAGS.IS_EXTERN = FLAGS.IS_STATIC = 0;
для выключения битов;
IF (FLAGS.IS_EXTERN == 0 &&FLAGS.IS_STATIC == 0)...
для их проверки.
Поле не может перекрывать границу INT; если указанная
ширина такова, что это должно случиться, то поле выравнива-
ется по границе следующего INT. Полям можно не присваивать
имена; неименованные поля (только двоеточие и ширина) ис-
пользуются для заполнения свободного места. Чтобы вынудить
выравнивание на границу следующего INT, можно использовать
специальную ширину 0.
· 147 -
При работе с полями имеется ряд моментов, на которые
следует обратить внимание. По-видимому наиболее существенным
является то, что отражая природу различных аппаратных сред-
ств, распределение полей на некоторых машинах осуществляется
слева направо, а на некоторых справа налево. Это означает,
что хотя поля очень полезны для работы с внутренне опреде-
ленными структурами данных, при разделении внешне определяе-
мых данных следует тщательно рассматривать вопрос о том, ка-
кой конец поступает первым.
Другие ограничения, которые следует иметь в виду: поля
не имеют знака; они могут храниться только в переменных типа
INT (или, что эквивалентно, типа UNSIGNED); они не являются
массивами; они не имеют адресов, так что к ним не применима
операция &.
6.8. Объединения.
Oбъединения - это переменная, которая в различные момен-
ты времени может содержать объекты разных типов и размеров,
причем компилятор берет на себя отслеживание размера и тре-
бований выравнивания. Объединения представляют возможность
работать с различными видами данных в одной области памяти,
не вводя в программу никакой машинно-зависимой информации.
В качестве примера, снова из символьной таблицы компиля-
тора, предположим, что константы могут быть типа INT , FLOAT
или быть указателями на символы. значение каждой конкретной
константы должно храниться в переменной соотвествующего ти-
па, но все же для управления таблицей самым удобным было бы,
если это значение занимало бы один и тот же объем памяти и
хранилось в том же самом месте независимо от его типа. это и
является назначением объединения - выделить отдельную пере-
менную, в которой можно законно хранить любую одну из пере-
менных нескольких типов. Как и в случае полей, синтаксис ос-
новывается на структурах.
UNION U_TAG \(
INT IVAL;
FLOAT FVAL;
CHAR *PVAL;
\) UVAL;
Переменная UVAL будет иметь достаточно большой размер,чтобы
хранить наибольший из трех типов, независимо от машины, на
которой осуществляется компиляция, - программа не будет за-
висить от характеристик аппаратных средств. Любой из этих
трех типов может быть присвоен UVAR и затем использован в
выражениях, пока такое использование совместимо: извлекаемый
тип должен совпадать с последним помещенным типом. Дело
программиста - следить за тем, какой тип хранится в объеди-
нении в данный момент; если что-либо хранится как один тип,
а извлекается как другой, то результаты будут зависеть от
используемой машины.
· 149 -
Синтаксически доступ к членам объединения осуществляется
следующим образом:
имя объединения.член
или
указатель объединения ->член
то есть точно так же, как и в случае структур. если для отс-
леживания типа, хранимого в данный момент в UVAL, использу-
ется переменная UTYPE, то можно встретить такой участок
программы:
IF (UTYPE == INT)
PRINTF(“%D\N”, UVAL.IVAL);
ELSE IF (UTYPE == FLOAT)
PRINTF(“%F\N”, UVAL.FVAL);
ELSE IF (UTYPE == STRING)
PRINTF(“%S\N”, UVAL.PVAL);
ELSE
PRINTF(“BAD TYPE %D IN UTYPE\N”, UTYPE);
Объединения могут появляться внутри структур и массивов
и наоборот. Запись для обращения к члену объединения в
структуре (или наоборот) совершенно идентична той, которая
используется во вложенных структурах. например, в массиве
структур, определенным следующим образом
STRUCT \(
CHAR *NAME;
INT FLAGS;
INT UTYPE;
UNION \(
INT IVAL;
FLOAT FVAL;
CHAR *PVAL;
\) UVAL;
\) SYMTAB[NSYM];
на переменную IVAL можно сослаться как
SYMTAB[I].UVAL.IVAL
а на первый символ строки PVAL как
*SYMTAB[I].UVAL.PVAL
В сущности объединение является структурой, в которой все
члены имеют нулевое смещение. Сама структура достаточно ве-
лика, чтобы хранить “самый широкий” член, и выравнивание
пригодно для всех типов, входящих в объединение. Как и в
случае структур, единственными операциями, которые в настоя-
щее время можно проводить с объединениями, являются доступ к
· 150 -
члену и извлечение адреса; объединения не могут быть присво-
ены, переданы функциям или возвращены ими. указатели объеди-
нений можно использовать в точно такой же манере, как и ука-
затели структур.
Программа распределения памяти, приводимая в главе 8 ,
показывает, как можно использовать объединение, чтобы сде-
лать некоторую переменную выровненной по определенному виду
границы памяти.
... основаниям. При этом философская абстракция языка оказывается неразрывно связана с основными темами и движениями философии в целом. Более конкретно, на ранние стадии традиционно рассматриваемого в рамках АФ анализа обыденного языка глубокое влияние оказала философия Дж. Э. Мура, особенно его учение о здравом смысле, согласно которому такие понятия, как «человек», «мир», «я», «внешний мир», « ...
... и других странах СНГ, а также облегчение доступа к русской и мировой культуре и науке. Таким образом, судя по данным наших исследований, востребованность русского языка осталась в республике достаточно высокой. Многие представители современной молдавской молодежи продолжают, как их отцы и деды, тянуться к русской культуре, научным и техническим достижениям России. Русский язык остается языком ...
... рисуночное словесно-слоговое письмо). Памятники среднеэламского периода (14—12 вв. до н.э.) выполнены аккадской клинописью. Памятники новоэламского периода относятся к 8—6 вв. до н.э. Был официальным языком в персидском государстве Ахеменидов в 6—4 вв. предполагается, что он, подвергшись влиянию древнеперсидского, сохранился до раннего средневековья. 7. Бурушаски язык Язык бурушаски ( ...
... /диалект), скифский, согдийский, среднеперсидский, таджикский, таджриши (язык/диалект), талышский, татский, хорезмийский, хотаносакский, шугнано-рушанская группа языков, ягнобский, язгулямский и др. Они относятся к индоиранской ветви индоевропейских языков. Области распространения: Иран, Афганистан, Таджикистан, некоторые районы Ирака, Турции, Пакистана, Индии, Грузии, Российской Федерации. Общее ...
0 комментариев