ниже перечисляются спецификаторы класса памяти:
спецификатор _
класса _
памяти:
auto static extern register typedef Спецификатор
typedef не резервирует память и называется"спецификатором класса памяти" только по синтаксическимсоображениям; это обсуждается ниже. Смысл различных классовпамяти был обсужден ранее (см. "Объекты языка Си"). Описания
auto,
static и
register служат также вкачестве определений в том смысле, что они вызывают резерви-рование нужного количества памяти. В случае
extern должноприсутствовать внешнее определение указываемых идентификато-ров где то вне функции, в которой они описаны. Описание
register лучше всего представлять себе какописание
auto вместе с намеком компилятору, что описанныетаким образом переменные будут часто использоваться. Эффек-тивны только несколько первых таких описаний. Кроме того, в
-22- регистрах могут храниться только переменные определенныхтипов; на CM-ЭВМ это
int,
char или указатель. Существует идругое ограничение на использование регистровых переменных:к ним нельзя применять операцию взятия адреса
&. При разум-ном использовании регистровых описаний можно ожидать получе-ния меньших по размеру и более быстрых программ, но в буду-щем улучшение генерирования кодов может сделать их ненуж-ными. В компиляторе для СМ ЭВМ воспринимаются первые 3 описа-ния
register в каждой функции. Описание может содержать не более одного спецификаторакласса памяти. Если описание не содержит спецификаторакласса памяти, то считается, что он имеет значение
auto,если описание находится внутри некоторой функции, и
extern впротивном случае. Исключение: функции никогда не бываютавтоматическими.
Спецификаторы типа
Ниже перечисляются спецификаторы типа.
спецификатор _
типа:
char short int long unsigned float double спецификатор _
структуры _
или _
объединения спецификатор _
перечисления определяющее _
тип _
имя Слова
long,
short и
unsigned можно рассматривать как прила-гательные; допустимы следующие комбинации:
short int long int unsigned int long float Последняя комбинация означает то же, что и
double. В осталь-ном описание может содержать не более одного спецификаторатипа. Если описание не содержит спецификатора типа, то счи-тается, что он имеет значение
int. Спецификаторы структур и объединений обсуждаются в п.0.5, спецификация перечислимого типа - в п.0.6; описания сопределяющими тип именами
typedef обсуждаются в п. 0.9.
-23-
Описатели
Входящий в описание список описателей представляетсобой последовательность разделенных запятыми описателей,каждый из которых может иметь инициализатор.
список _
описателей:
инициализируемый _
описатель инициализируемый _
описатель,
спи -
сок _
описателей инициализируемый _
описатель:
описатель инициализатор необ Инициализаторы описываются в п.0.6. Спецификаторы и описанияуказывают тип и класс памяти объектов, на которые ссылаютсяописатели. Описатели имеют следующий синтаксис:
описатель:
идентификатор (
описатель)
* описатель описатель ()
описатель [
константное -
выражение ]
необ Группирование такое же, как и в выражениях.
Смысл описателей
Каждый описатель рассматривается как утверждение того,что когда конструкция той же самой формы, что и описатель,появляется в выражении, то она выдает объект указанного типаи указанного класса памяти. Каждый описатель содержит ровноодин идентификатор; это именно тот идентификатор, который иописывается. Если в качестве описателя появляется просто идентифика-тор, то он имеет тип, указываемый в специфицирующем заго-ловке описания. Описатель в круглых скобках идентичен описателю безкруглых скобок, но круглые скобки могут изменять связи всоставных описателях. Примеры смотри ниже. Представим себе описание
t di где
t - спецификатор типа (подобный
int и т.д.), а
di - опи-сатель. Предположим, что это описание приводит к тому, чтосоответствующий идентификатор имеет тип...
t, где "..."пусто, если
di просто отдельный идентификатор (так что тип
х -24- в
int х просто
int). Тогда, если
di имеет форму
*d то содержащийся идентификатор будет иметь тип...
указательна t. Если
di имеет форму
d () то содержащийся идентификатор имеет тип...
функция,
возвра-щающая t. Если
di имеет форму
d [
константное _
выражение ] или
d [ ] то содержащийся идентификатор имеет тип...
массив t. В пер-вом случае константным выражением является выражение, значе-ние которого можно определить во время компиляции и котороеимеет тип
int. (точное определение константного выражениядано ниже). Когда несколько спецификаций вида "массив из"оказываются примыкающими, то создается многомерный массив;константное выражение, задающее границы массивов, можетотсутствовать только у первого члена этой последователь-ности. Такое опускание полезно, когда массив является внеш-ним или формальным и его фактическое определение, котороевыделяет память, приводится в другом месте. Первое констант-ное выражение может быть опущено также тогда, когда за опи-сателем следует инициализация. В этом случае размер опреде-ляется по числу приведенных инициализируемых элементов. Массив может быть образован из элементов одного изосновных типов, из указателей, из структур или объединенийили из других массивов (чтобы образовать многомерный мас-сив). Не все возможности, которые разрешены с точки зренияуказанного выше синтаксиса, фактически допустимы. Имеютсяследующие ограничения: функции не могут возвращать массивыили функции, хотя они могут возвращать указатели на такиевещи; не существует массивов функций, хотя могут быть мас-сивы указателей на функции. Аналогично, структуры или объе-динения не могут содержать функцию, но они могут содержатьуказатель на функцию. В качестве примера рассмотрим описание
-25- int i,
*ip,
f (),
*fip (), (
*pfi)(); в котором описывается целое
i, указатель
ip на целое, функ-ция
f, возвращающая целое, функция
fip, возвращающая указа-тель на целое, и указатель
pfi на функцию, которая возвра-щает целое. Особенно полезно сравнить два последних описа-теля. Связь в
*fip () можно представить в виде
*(fip ()), такчто описанием предполагается, что в выражении требуетсяобращение к функции
fip и последующее использование косвен-ной адресации для выдачи с помощью полученного результата(указателя) целого. В описателе (
*pfi)() дополнительныескобки необходимы, поскольку они точно так же, как и в выра-жении, указывают, что косвенная адресация через указательвыдает функцию, которая затем вызывается; эта вызваннаяфункция возвращает целое. В качестве другого примера приведем описание
float fa [17],
*afp [17]; в котором описывается массив чисел типа
float и массив ука-зателей на числа типа
float. Наконец,
static int х3d [3][5][7]; описывает статический трехмерный массив целых размером3*5*7. Более подробно:
х3d является массивом из трех элемен-тов; каждый элемент является массивом пяти массивов; каждыйпоследний массив является массивом из семи целых. Каждое извыражений
х3d,
х3d [
i ],
х3d [
i ][
j ] и
х3d [
i ][
j ][
k ] может разум-ным образом появляться в выражениях. Первые три имеют тип"массив", последнее имеет тип
int.