Смекни!
smekni.com

в противном случае одно выражение должно быть указателем, а

другое - константой 0, и результат будет иметь тип указате-

ля. Вычисляется только одно из второго и третьего выражений.

· 199 -

15.14. Операция присваивания

Имеется ряд операций присваивания, каждая из которых

группируется слева направо. Все операции требуют в качестве

своего левого операнда L-значение, а типом выражения присва-

ивания является тип его левого операнда. Значением выражения

присваивания является значение, хранимое в левом операнде

после того, как присваивание уже будет произведено. Две час-

ти составной операции присваивания являются отдельными лек-

семами.

Выражение-присваивания:

L-значение = выражение

L-значение += выражение

L-значение -= выражение

L-значение *= выражение

L-значение /= выражение

L-значение %= выражение

L-значение >>= выражение

L-значение <<= выражение

L-значение &= выражение

L-значение ^= выражение

L-значение &bsol;!= выражение

Когда производится простое присваивание C'=', значение

выражения заменяет значение объекта, на которое ссылается

L-значение. Если оба операнда имеют арифметический тип, то

перед присваиванием правый операнд преобразуется к типу ле-

вого операнда.

О свойствах выражения вида E1 оп = E2, где Oп - одна из

перечисленных выше операций, можно сделать вывод, если

учесть, что оно эквивалентно выражению E1 = E1 оп (E2); од-

нако выражение E1 вычисляется только один раз. В случае опе-

раций += и -= левый операнд может быть указателем, причем

при этом (целочисленный) правый операнд преобразуется таким

образом, как объяснено в п. 15.4; все правые операнды и все

отличные от указателей левые операнды должны иметь арифмети-

ческий тип.

Используемые в настоящее время компиляторы допускают

присваивание указателя целому, целого указателю и указателя

указателю другого типа. такое присваивание является чистым

копированием без каких-либо преобразований. Такое употребле-

ние операций присваивания является непереносимым и может

приводить к указателям, которые при использовании вызывают

ошибки адресации. Тем не менее гарантируется, что присваива-

ние указателю константы 0 дает нулевой указатель, который

можно отличать от указателя на любой объект.

15.15. Операция запятая Выражение-с-запятой:

выражение , выражение

·
200 -

Пара выражений, разделенных запятой, вычисляется слева нап-

раво и значение левого выражения отбрасывается. Типом и зна-

чением результата является тип и значение правого операнда.

Эта операция группируется слева направо. В контексте, где

запятая имеет специальное значение, как, например, в списке

фактических аргументов функций (п. 15.1) Или в списках ини-

циализаторов (п. 16.6), Операция запятая, описываемая в этом

разделе, может появляться только в круглых скобках; напри-

мер, функция

F(A,(T=3,T+2),C)

имеет три аргумента, второй из которых имеет значение 5.

16. Описания

Описания используются для указания интерпретации, кото-

рую язык “C” будет давать каждому идентификатору; они не

обязательно резервируют память, соответствующую идентифика-

тору. Описания имеют форму

Описание:

спецификаторы-описания список-описателей

необ;

Описатели в списке описателей содержат описываемые идентифи-

каторы. Спецификаторы описания представляют собой последова-

тельность спецификаторов типа и спецификаторов класса памя-

ти.

Спецификаторы-описания:

спецификатор-типа спецификаторы-описания

необ

спецификатор-класса-памяти спецификатор-описания

необ

список должен быть самосогласованным в смысле, описываемом

ниже.

16.1. Спецификаторы класса памяти Ниже перечисляются спецификаторы класса памяти:

Спецификатор-класса-памяти:

AUTO

STATIC

EXTERN

REGISTER

TYPEDEF

Спецификатор TYPEDEF не реализует памяти и называется

“спецификатором класса памяти” только по синтаксическим со-

ображениям; это обсуждается в п. 16.8. Смысл различных клас-

сов памяти был обсужден в п. 12.

Описания AUTO, STATIC и REGISTER служат также в качестве

определений в том смысле, что они вызывают резервирование

нужного количества памяти. В случае EXTERN должно присутст-

вовать внешнее определение (п. 18) Указываемых идентификато-

ров где-то вне функции, в которой они описаны.

· 201 -

Описание REGISTER лучше всего представлять себе как опи-

сание AUTO вместе с намеком компилятору, что описанные таким

образом переменные будут часто использоваться. Эффективны

только несколько первых таких описаний. Кроме того, в регис-

трах могут храниться только переменные определенных типов;

на PDP-11 это INT, CHAR или указатель. Существует и другое

ограничение на использование регистровых переменных: к ним

нельзя применять операцию взятия адреса &. При разумном ис-

пользовании регистровых описаний можно ожидать получения

меньших по размеру и более быстрых программ, но улучшение в

будущем генерирования кодов может сделать их ненужными.

Описание может содержать не более одного спецификатора

класса памяти. Если описание не содержит спецификатора клас-

са памяти, то считается, что он имеет значение AUTO, если

описание находится внутри некоторой функции, и EXTERN в про-

тивном случае. исключение: функции никогда не бывает автома-

тическими.

16.2. Спецификаторы типа

Ниже перечисляются спецификаторы типа.

Спецификатор-типа:

CHAR

SHORT

INT

LONG

UNSIGNED

FLOAT

DOUBLE

спецификатор-структуры-или-объединения

определяющее-тип-имя

Слова LONG, SHORT и USIGNED можно рассматривать как при-

лагательные; допустимы следующие комбинации:

SHORT INT

LONG INT

USIGNED INT

LONG FLOAT

Последняя комбинация означает то же, что и DOUBLE. В осталь-

ном описание может содержать не более одного спецификатора

типа. Если описание не содержит спецификатора типа, то счи-

тается, что он имеет значение INT.

Спецификаторы структур и объединений обсуждаются в п.

16.5; Описания с определяющими тип именами TYPEDEF обсужда-

ются в п. 16.8.

· 202 -

16.3. Описатели

Входящий в описание список описателей представляет собой

последовательность разделенных запятыми описателей, каждый

из которых может иметь инициализатор.

Список-описателей:

инициализируемый-описатель

инициализируемый-описатель, список-описателей

инициализируемый-описатель:

описатель-инициализатор

необ

Инициализаторы описываются в п. 16.6. Спецификаторы и описа-

ния указывают тип и класс памяти объектов, на которые ссыла-

ются описатели. Описатели имеют следующий синтаксис:

описатель:

идентификатор

( описатель )

· описатель описатель () описатель [константное-выражение

необ]

Группирование такое же как и в выражениях.

16.4. Смысл описателей

Каждый описатель рассматривается как утверждение того,

что когда конструкция той же самой формы, что и описатель,

появляется в выражении, то она выдает объект указанного типа

и указанного класса памяти. Каждый описатель содержит ровно

один идентификатор; это именно тот идентификатор, который и

описывается.

Если в качестве описателя появляется просто идентифика-

тор, то он имеет тип, указываемый в специфицирующем заголов-

ке описания.

Описатель в круглых скобках идентичен описателю без

круглых скобок, но круглые скобки могут изменять связи в

составных описателях. Примеры смотри ниже.

Представим себе описание

T DI

где T - спецификатор типа (подобный INT и т.д.), а DI - опи-

сатель. Предположим, что это описание приводит к тому, что

соответствующий идентификатор имеет тип “...T”, где “...”

пусто, если DI просто отдельный идентификатор (так что тип X

в “INT X” просто INT). Тогда , если DI имеет форму

*D

то содержащийся идентификатор будет иметь тип “... Указатель

на T”.

· 203 -

Если DI имеет форму

D()

то содержащийся идентификатор имеет тип “... Функция, возв-

ращающая T”.

Если DI имеет форму

D[константное-выражение]

или

D[ ]

то содержащийся идентификатор имеет тип “...массив T”. В

первом случае константным выражением является выражение,

значение которого можно определить во время компиляции и ко-

торое имеет тип INT. (Точное определение константного выра-

жения дано в п. 23). Когда несколько спецификаций вида “мас-

сив из” оказываются примыкающими, то создается многомерный

массив; константное выражение, задающее границы массивов,

может отсутствовать только у первого члена этой последова-

тельности. Такое опускание полезно, когда массив является

внешним и его фактическое определение, которое выделяет па-

мять, приводится в другом месте. Первое константное выраже-

ние может быть опущено также тогда, когда за описателем сле-

дует инициализация. В этом случае размер определяется по

числу приведенных инициализируемых элементов.

Массив может быть образован из элементов одного из ос-

новных типов, из указателей, из структур или объединений или

из других массивов (чтобы образовать многомерный массив).

Не все возможности, которые разрешены с точки зрения

указанного выше синтаксиса, фактически допустимы. Имеются

следующие ограничения: функции не могут возвращать массивы,

структуры, объединения или функции, хотя они могут возвра-

щать указатели на такие вещи; не существует массивов функ-

ций, хотя могут быть массивы указателей на функции. Анало-

гично, структуры или объединения не могут содержать функцию,

но они могут содержать указатель на функцию.

В качестве примера рассмотрим описание

INT I, *IP, F(), *FIP(), (*PFI)();

в котором описывается целое I, указатель IP на целое, функ-

ция F, возвращающая целое, функция FIP, возвращающая указа-

тель на целое, и указатель PFI на функцию, которая возвраща-