* 9. Приложение А: справочное руководство по языку 'C' *





    9.1. Введение






Это руководство описывает язык 'с' для компьютеров DEC
PDP-11, HONEYWELL 6000, IBM система/370 и INTERDATA 8/32.
там, где есть расхождения, мы сосредотачиваемся на версии
для PDP-11, стремясь в то же время указать детали, которые
зависят от реализации. За малым исключением, эти расхождения
непосредственно обусловлены основными свойствами используе-
мого аппаратного оборудования; различные компиляторы обычно
вполне совместимы.


    10. Лексические соглашения




Имеется шесть классов лексем: идентификаторы, ключевые
слова, константы, строки, операции и другие разделители.
Пробелы, табуляции , новые строки и комментарии (совместно,
"пустые промежутки"), как описано ниже, игнорируются, за ис-
ключением тех случаев, когда они служат разделителями лек-
сем. Необходим какой-то пустой промежуток для разделения
идентификаторов, ключевых слов и констант, которые в против-
ном случае сольются.
Если сделан разбор входного потока на лексемы вплоть до
данного символа, то в качестве следующей лексемы берется са-
мая длинная строка символов, которая еще может представлять
собой лексему.


    10.1. Комментарии



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


    10.2. Идентификаторы (имена)



Идентификатор - это последовательность букв и цифр; пер-
вый символ должен быть буквой. Подчеркивание _ считается
буквой. Буквы нижнего и верхнего регистров различаются. зна-
чащими являются не более, чем первые восемь символов, хотя
можно использовать и больше. На внешние идентификаторы, ко-
торые используются различными ассемблерами и загрузчиками,
накладыватся более жесткие ограничения:

DEC PDP-11 7 символов, 2 регистра
HONEYWELL 6000 6 символов, 1 регистр
IBM 360/370 7 символов, 1 регистр
INTERDATA 8/32 8 символов, 2 регистра




    10.3. Ключевые слова




Следующие идентификаторы зарезервированы для использова-
ния в качестве ключевых слов и не могут использоваться иным
образом:

INT EXTERN ELSE
CHAR REGISTER FOR
FLOAT TYPEDEF DO
DOUBLE STATIC WHILE
STRUCT GOTO SWITCH
UNION RETURN CASE
LONG SIZEOF DEFAULT
SHORT BREAK ENTRY
UNSIGNED CONTINUE
*AUTO IF

Ключевое слово ENTRY в настоящее время не используется ка-
ким-либо компилятором; оно зарезервировано для использования
в будущем. В некоторых реализациях резервируется также слова
FORTRAN и ASM

    10.4. Константы



Имеется несколько видов констант, которые перечислены ниже.
В пункте 10.6 резюмируются характеристики аппаратных сред-
ств, которые влияют на размеры.

    10.4.1. Целые константы






Целая константа, состоящая из последовательности цифр,
считается восьмеричной, если она начинается с 0 (цифра
нуль), и десятичной в противном случае. Цифры 8 и 9 имеют
восьмеричные значения 10 и 11 соответственно. Последователь-
ность цифр, которой предшествуют символы 0х (нуль, х-малень-
кое) или 0х (нуль х-большое), рассматривается как шестнадца-
тиричное целое. Шестнадцатиричные цифры включают буквы от а
(маленькое) или а (большое) до F (маленькое) или F (большое)
со значениями от 10 до 15. Десятичная константа, величина
которой превышает наибольшее машинное целое со знаком, счи-
тается длинной; восмеричная или шестнадцатиричная константа,
которое превышает наибольшее машинное целое без знака, также
считается длинной.

    10.4.2. Явные длинные константы



Десятичная, восмеричная или шестнадцатиричная константа,
за которой непосредственно следует L (эль-маленькое) или L
(эль-большое), является длинной константой. Как обсуждается
ниже, на некоторых машинах целые и длинные значения могут
рассматриваться как идентичные.

    10.4.3. Символьные константы



Символьная константа - это символ, заключенный в одиноч-
ные кавычки, как, например, 'X'. Значением символьной конс-
танты является численное значение этого символа в машинном
представлении набора символов.



Некоторые неграфические символы, одиночная кавычка ' и
обратная косая черта \ могут быть представлены в соответст-
вии со следующей таблицей условных последовательностей:

новая строка NL/LF/ \N
горизонтальная табуляция HT \T
символ возврата на одну позицию BS \B
возврат каретки CR \R
переход на новую страницу FF \F
обратная косая черта \ \\
одиночная кавычка ' \'
комбинация битов DDD \DDD

Условная последовательность \DDD состоит из обратной ко-
сой черты, за которой следуют 1,2 или 3 восмеричных цифры,
которые рассмативаются как задающие значение желаемого сим-
вола. Специальным случаем этой конструкции является последо-
вательность \0 (за нулем не следует цифра), которая опреде-
ляет символ NUL. если следующий за обратной косой чертой
символ не совпадает с одним из указанных, то обратная косая
черта игнорируется.

    10.4.4. Плавающие константы



Плавающая константа состоит из целой части, десятичной
точки, дробной части, буквы E (маленькая) или E (большая) и
целой экспоненты с необязательным знаком. Как целая, так и
дробная часть являются последовательностью цифр. Либо целая,
либо дробная часть (но не обе) может отсутствовать; либо де-
сятичная точка, либо е (маленькая) и экспонента (но не то и
другое одновременно) может отсутствовать. Каждая плавающая
константа считается имеющей двойную точность.

    10.5. Строки



Строка - это последовательность символов, заключенная в
двойные кавычки, как, наприимер,"...". Строка имеет тип
"массив массивов" и класс памяти STATIC (см. Пункт 4 ниже).
Строка инициализирована указанными в ней символами. Все
строки, даже идентично записанные, считаются различными.
Компилятор помещает в конец каждой строки нулевой байт \0, с
тем чтобы просматривающая строку программа могла определить
ее конец. Перед стоящим внутри строки символом двойной ка-
вычки " должен быть поставлен символ обратной косой черты \;
кроме того, могут использоваться те же условия последова-
тельности, что и в символьных константах. И последнее, об-
ратная косая черта \, за которой непосредственно следует
символ новой строки, игнорируется.




    10.6. Характеристики аппаратных средств



Следующая ниже таблица суммирует некоторые свойства ап-
паратного оборудования, которые меняются от машины к машине.
Хотя они и влияют на переносимость программ, на практике они
представляют маленькую проблему, чем это может казаться за-
ранее.
Таблица 1
-------------------------------------------------------
DEC PDP-11 HONEYWELL IBM 370 INTERDATA 8/32
ASCII ASCII EBCDIC ASCII
CHAR 8 BITS 9 BITS 8 BITS 8 BITS
INT 16 36 32 32
SHORT 16 36 16 16
LONG 32 36 32 32
FLOAT 32 36 32 32
DOUBLE 64 72 64 64
RANGE -38/+38 -38/+38 -76/+76 -76/+76
--------------------------------------------------------

    11. Синтаксическая нотация




В используемой в этом руководстве синтаксической нотации
синтаксические категории выделяются курсивом (прим. перев.:
в настоящее время синтексические категории вместо курсивом
выделяются подчеркиванием), а литерные слова и символы -
жирным шрифтом. Альтернативные категории перечисляются на
отдельных строчках. Необязательный символ, терминальный или
нетерминальный, указывается индексом "необ", так что

\( выражение
--------- необ \)

указывает на необязательное выражение, заключенное в фигур-
ных скобках. Синтаксис суммируется в пункте 18.


    12. Что в имени тебе моем?



Язык "C" основывает интерпретацию идентификатора на двух
признаках идентификатора: его классе памяти и его типе.
Класс памяти определяет место и время хранения памяти, свя-
занной с идентификатором; тип определяет смысл величин, на-
ходящихся в памяти, определенной под идентификатором.
Имеются четыре класса памяти: автоматическая, статичес-
кая, внешняя и регистровая. Автоматические переменные явля-
ются локальными для каждого вызова блока и исчезают при вы-
ходе из этого блока. Статические переменные являются локаль-
ными, но сохраняют свои значения для следующего входа в блок
даже после того, как управление передается за пределы блока.
Внешние переменные существуют и сохраняют свои значения в
течение выполнения всей программы и могут использоваться для
связи между функциями, в том числе и между независимо ском-
пилированными функциями. Регистровые переменные хранятся
(ели это возможно) в быстрых регистрах машины; подобно авто-
матическим переменным они являются локальными для каждого
блока и исчезают при выходе из этого блока.



В языке "C" предусмотрено несколько основных типов
объектов:
объекты, написанные как символы (CHAR), достаточно вели-
ки, чтобы хранить любой член из соответствующего данной реа-
лизации внутреннего набора символов, и если действительный
символ из этого набора символов хранится в символьной пере-
менной, то ее значение эквивалентно целому коду этого симво-
ла. В символьных переменных можно хранить и другие величины,
но реализация будет машинно-зависимой.
Можно использовать до трех размеров целых, описываемых
как SHORT INT, INT и LONG INT. Длинные целые занимают не
меньше памяти, чем короткие, но в конкретной реализации мо-
жет оказаться, что либо короткие целые, либо длинные целые,
либо те и другие будут эквивалентны простым целым. "Простые"
целые имеют естественный размер, предусматриваемый архиитек-
турой используемой машины; другие размеры вводятся для удво-
летворения специальных потребностей.
Целые без знака, описываемые как UNSIGNED, подчиняются
законам арифметики по модулю 2**N, где N - число битов в их
представлении. (На PDP-11 длинные величины без знака не пре-
дусмотрены).
Плавающие одинарной точности (FLOAT) и плавающие двойной
точности (DOUBLE) в некоторых реализациях могут быть синони-
мами.
Поскольку объекты упомянутых выше типов могут быть ра-
зумно интерпретированы как числа, эти типы будут называться
арифметическими. типы CHAR и INT всех размеров совместно бу-
дут называться целочисленными. Типы FLOAT и DOUBLE совместно
будут называться плавающими типами.
Кроме основных арифметических типов существует концепту-
ально бесконечный класс производных типов, которые образуют-
ся из основных типов следующим образом:
массивы объектов большинства типов;
функции, которые возвращают объекты заданного типа;
указатели на объекты данного типа;
структуры, содержащие последовательность объектов
различных типов;
объединения, способные содержать один из нескольких
объектов различных типов.
Вообще говоря, эти методы построения объектов могут при-
меняться рекурсивно.


    13. Объекты и L-значения



Объект является доступным обработке участком памяти;
L-значение - это выражение, ссылающееся на объект. Очевидным
примером выражения L-значения является идентификатор. Сущес-
твуют операции, результатом которых являются L-значения; ес-
ли, например, E - выражение указанного типа, то *E является
выражением L-значения, ссылающимся на объект E. Название
"L-значение" происходит от выражения присваивания E1=E2, в
котором левая часть должна быть выражением L-значения. При
последующем обсуждении каждой операции будет указываться,
ожидает ли она операндов L-значения и выдает ли она L-значе-
ние.



    14. Преобразования




Ряд операций может в зависимости от своих операндов вы-
зывать преобразование значение операнда из одного типа в
другой. В этом разделе объясняются результаты, которые сле-
дует ожидать от таких преобразований. В п. 14.6 Подводятся
итоги преобразований, требуемые большинством обычных опера-
ций; эти сведения дополняются необходимым образом при обсуж-
дении каждой операции.


    14.1. Символы и целые



Символ или короткое целое можно использовать всюду, где
можно использовать целое. Во всех случаях значение преобра-
зуется к целому. Преобразование более короткого целого к бо-
лее длинному всегда сопровождается знаковым расширением; це-
лые являются величинами со знаком. Осуществляется или нет
знаковое расширение для символов, зависит от используемой
машины, но гарантируется, что член стандартного набора сим-
волов неотрицателен. из всех машин, рассматриваемых в этом
руководстве, только PDP-11 осуществляет знаковое расширение.
область значений символьных переменных на PDP-11 меняется от
-128 до 127; символы из набора ASC11 имеют положительные
значения. Символьная константа, заданная с помощью восьме-
ричной условной последовательности, подвергается знаковому
расширению и может оказаться отрицательной; например, '\377'
имеет значение -1.
Когда более длинное целое преобразуется в более короткое
или в CHAR, оно обрезается слева; лишние биты просто отбра-
сываются.


    14.2. Типы FLOAT и DOUBLE



Вся плавающая арифметика в "C" выполняется с двойной
точностью каждый раз, когда объект типа FLOAT появляется в
выражении, он удлиняется до DOUBLE посредством добавления
нулей в его дробную часть. когда объект типа DOUBLE должен
быть преобразован к типу FLOAT, например, при присваивании,
перед усечением DOUBLE округляется до длины FLOAT.

    14.3. Плавающие и целочисленные величины



Преобразование плавающих значений к целочисленному типу
имеет тенденцию быть до некоторой степени машинно-зависимым;
в частности направление усечения отрицательных чисел меняет-
ся от машине к машине. Результат не определен, если значение
не помещается в предоставляемое пространство.
Преобразование целочисленных значений в плавающие выпол-
няется без осложнений. Может произойти некоторая потеря точ-
ности, если для результата не содержится достаточного коли-
чества битов.

    14.4. Указатели и целые



Целое или длинное целое может быть прибавлено к указате-
лю или вычтено из него; в этом случае первая величина преоб-
разуется так, как указывается в разделе описания операции
сложения.



Два указателя на объекты одинакового типа могут быть
вычтены; в этом случае результат преобразуется к целому, как
указывается в разделе описания операции вычитания.

    14.5. Целое без знака



Всякий раз, когда целое без знака объединяется с простым
целым, простое целое преобразуется в целое без знака и ре-
зультат оказывается целым без знака. Значением является наи-
меньшее целое без знака, соответствующее целому со знаком
(по модулю 2**размер слова). В двоичном дополнительном пред-
ставлении это преобразование является чисто умозрительным и
не изменяет фактическую комбинацию битов.
Когда целое без знака преобразуется к типу LONG, значе-
ние результата совпадает со значением целого без знака. Та-
ким образом, это преобразование сводится к добавлению нулей
слева.

    14.6. Арифметические преобразования



Подавляющее большинство операций вызывает преобразование
и определяет типы результата аналогичным образом. Приводимая
ниже схема в дальнейшем будет называться "обычными арифмети-
ческими преобразованиями".
Сначала любые операнды типа CHAR или SHORT преобразуются в
INT, а любые операнды типа FLOAT преобразуются в DOUBLE.
Затем, если какой-либо операнд имеет тип DOUBLE, то другой
преобразуется к типу DOUBLE, и это будет типом результата.
В противном случае, если какой-либо операнд имеет тип LONG,
то другой операнд преобразуется к типу LONG, и это и будет
типом результата.
В противном случае, если какой-либо операнд имеет тип
UNSIGNED, то другой операнд преобразуется к типу UNSIGNED,
и это будет типом результата.
В противном случае оба операнда будут иметь тип INT, и это
будет типом результата.


    15. Выражения



Старшинство операций в выражениях совпадает с порядком
следования основных подразделов настоящего раздела, начиная
с самого высокого уровня старшинства. Так, например, выраже-
ниями, указываемыми в качестве операндов операции +
(п.15.4), Являются выражения, определенные в п.п.15.1-15.3.
Внутри каждого подраздела операции имеет одинаковое старшин-
ство. В каждом подразделе для описываемых там операций ука-
зывается их ассоциативность слева или справа. Старшинство и
ассоциативность всех операций в выражениях резюмируются в
грамматической сводке в п.18.
В противном случае порядок вычислений выражений не опре-
делен. В частности, компилятор считает себя в праве вычис-
лять подвыражения в том порядке, который он находит наиболее
эффективным, даже если эти подвыражения приводят к побочным
эффектам. Порядок, в котором происходят побочные эффекты, не
специфицируется. Выражения, включающие коммутативные и ассо-
циативные операции ( *,+,&,!,^ ), могут быть переупорядочены
произвольным образом даже при наличии круглых скобок; чтобы
вынудить определенный порядок вычислений, в этом случае не-
обходимо использовать явные промежуточные переменные.



При вычислении выражений обработка переполнения и про-
верка при делении являются машинно-зависимыми. Все существу-
ющие реализации языка "C" игнорируют переполнение целых; об-
работка ситуаций при делении на 0 и при всех особых случаях
с плавающими числами меняется от машины к машине и обычно
выполняется с помощью библиотечной функции.

    15.1. Первичные выражения



Первичные выражения, включающие ., ->, индексацию и об-
ращения к функциям, группируются слева направо.

Первичное выражение:
идентификатор
константа
строка
(выражение)
первичное-выражение [выражение]
первичное-выражение (список-выражений нео
первичное-L-значение . Идентификатор
первичное-выражение -> идентификатор
список-выражений:
выражение
список-выражений, выражение

Идентификатор является первичным выражением при условии, что
он описан подходящим образом, как это обсуждается ниже. тип
идентификатора определяется его описанием. Если, однако, ти-
пом идентификатора является "массив ...", то значением выра-
жения, состоящего из этого идентификатора , является указа-
тель на первый объект в этом массиве, а типом выражения бу-
дет "указатель на ...". Более того, идентификатор массива не
является выражением L-значения. подобным образом идентифика-
тор, который описан как "функция, возвращающая ...", за иск-
лючением того случая, когда он используется в позиции имени
функции при обращении, преобразуется в "указатель на функ-
цию, которая возвращает ...".
Константа является первичным выражением. В зависимости
от ее формы типом константы может быть INT, LONG или DOUBLE.
Строка является первичным выражением. Исходным ее типом
является "массив символов"; но следуя тем же самым правилам,
которые приведены выше для идентификаторов, он модифицирует-
ся в "указатель на символы", и результатом является указа-
тель на первый символ строки. (имеется исключение в некото-
рых инициализаторах; см. П. 16.6.)
Выражение в круглых скобках является первичным выражени-
ем, тип и значение которого идентичны типу и значению этого
выражения без скобок. Наличие круглых скобок не влияет на
то, является ли выражение L-значением или нет.



Первичное выражение, за которым следует выражение в
квадратных скобках, является первичным выражением. Интуитив-
но ясно, что это выражение с индексом. Обычно первичное вы-
ражение имеет тип "указатель на ...", индексное выражение
имеет тип INT, а типом результата является "...". Выражение
E1[E2] по определению идентично выражению * ((E1) + (E2)).
Все, что необходимо для понимания этой записи, содержится в
этом разделе; вопросы, связанные с понятием идентификаторов
и операций * и + рассматриваются в п.п. 15.1, 15.2 И 15.4
соответственно; выводы суммируются ниже в п. 22.3.
Обращение к функции является первичным выражением, за
которым следует заключенный в круглые скобки возможно пустой
список выражений, разделенных запятыми, которые и представ-
ляют собой фактические аргументы функции. Первичное выраже-
ние должно быть типа "функция, возвращающая ...", а резуль-
тат обращения к функции имеет тип "...". Как указывается ни-
же, ранее не встречавщийся идентификатор, за которым непос-
редственно следует левая круглая скобка, считается описанным
по контексту, как представляющий функцию, возвращающую це-
лое; следовательно чаще всего встречающийся случай функции,
возвращающей целое значение, не нуждается в описании.
Перед обращением любые фактические аргументы типа FLOAT
преобразуются к типу DOUBLE, любые аргументы типа CHAR или
SHORT преобразуются к типу INT, и, как обычно, имена масси-
вов преобразуются в указатели. Никакие другие преобразования
не выполняются автоматически; в частности, не сравнивает ти-
пы фактических аргументов с типами формальных аргументов.
Если преобразование необходимо, используйте явный перевод
типа (CAST); см. П.п. 15.2, 16.7.
При подготовке к вызову функции делается копия каждого
фактического параметра; таким образом, все передачи аргумен-
тов в языке "C" осуществляются строго по значению. функция
может изменять значения своих формальных параметров, но эти
изменения не влияют на значения фактических параметров. С
другой строны имеется возможность передавать указатель при
таком условии, что функция может изменять значение объекта,
на который этот указатель указывает. Порядок вычисления ар-
гументов в языке не определен; обратите внимание на то, что
различные компиляторы вычисляют по разному.
Допускаются рекурсивные обращения к любой функции.
Первичное выражение, за которым следует точка и иденти-
фикатор, является выражением. Первое выражение должно быть
L-значением, именующим структуру или объединение, а иденти-
фикатор должен быть именем члена структуры или объединения.
Результатом является L-значение, ссылающееся на поименован-
ный член структуры или объединения.
Первичное выражение, за которым следует стрелка (состав-
ленная из знаков - и >) и идентификатор, является выражени-
ем. первое выражение должно быть указателем на структуру или
объединение, а идентификатор должен именовать член этой
структуры или объединения. Результатом является L-значение,
ссылающееся на поименованный член структуры или объединения,
на который указывает указательное выражение.
Следовательно, выражение E1->MOS является тем же самым,
что и выражение (*E1).MOS. Структуры и объединения рассмат-
риваются в п. 16.5. Приведенные здесь правила использования
структур и объединений не навязываются строго, для того что-
бы иметь возможность обойти механизм типов. См. П. 22.1.




    15.2. Унарные операции



Выражение с унарными операциями группируется справо на-
лево.
Унарное-выражение:
* выражение
& L-значение
- выражение
! Выражение
\^ выражение
++ L-значение
-- L-значение
L-значение ++
L-значение --
(имя-типа) выражение
SIZEOF выражение
SIZEOF имя-типа

Унарная операция * означает косвенную адресацию: выраже-
ние должно быть указателем, а результатом является L-значе-
ние, ссылающееся на тот объект, на который указывает выраже-
ние. Если типом выражения является "указатель на...", то ти-
пом результата будет "...".
Результатом унарной операции & является указатель на
объект, к которому ссылается L-значение. Если L-значение
имеет тип "...", то типом результата будет "указатель на
...".
Результатом унарной операции - (минус) является ее опе-
ранд, взятый с противоположным знаком. Для величины типа
UNSIGNED результат получается вычитанием ее значения из 2**N
(два в степени N), где N-число битов в INT. Унарной операции
+ (плюс) не существует.
Результатом операции логического отрицания ! Является 1,
если значение ее операнда равно 0, и 0, если значение ее
операнда отлично от нуля. Результат имеет тип INT. Эта опе-
рация применима к любому арифметическому типу или указате-
лям.
Операция \^ дает обратный код, или дополнение до едини-
цы, своего операнда. Выполняются обычные арифметические пре-
образования. Операнд должен быть целочисленного типа.
Объект, на который ссылается операнд L-значения префикс-
ной операции ++, увеличивается. значением является новое
значение операнда, но это не L-значение. Выражение ++х экви-
валентно х+=1. Информацию о преобразованиях смотри в разборе
операции сложения (п. 15.4) и операции присваивания (п.
15.14).
Префиксная операция -- аналогична префиксной операции
++, но приводит к уменьшению своего операнда L-значения.
При применении постфиксной операции ++ к L-значению ре-
зультатом является значение объекта, на который ссылается
L-значение. После того, как результат принят к сведению,
объект увеличивается точно таким же образом, как и в случае
префиксной операции ++. Результат имеет тот же тип, что и
выражение L-значения.



При применении постфиксной операции -- к L-значению ре-
зультатом является значение объекта, на который ссылается
L-значение. После того, как результат принят к сведению,
объект уменьшается точно таким же образом, как и в случае
префиксной операции --. Результат имеет тот же тип, что и
выражение L-значения.
Заключенное в круглые скобки имя типа данных,стоящее пе-
ред выражением , вызывает преобразование значения этого вы-
ражения к указанному типу. Эта конструкция называется пере-
вод (CAST). Имена типов описываются в п. 16.7.
Операция SIZEOF выдает размер своего операнда в байтах.
(Понятие байт в языке не определено, разве только как значе-
ние операции SIZEOF. Однако во всех существующих реализациях
байтом является пространство, необходимое для хранения
объекта типа CHAR). При применении к массиву результатом яв-
ляется полное число байтов в массиве. Размер определяется из
описаний объектов в выражении. Это выражение семантически
является целой константой и может быть использовано в любом
месте, где требуется константа. Основное применение эта опе-
рация находит при связях с процедурами, подобным распредели-
телям памяти, и в системах ввода- вывода.
Операция SIZEOF может быть также применена и к заключен-
ному в круглые скобки имени типа. В этом случае она выдает