Реферат: Язык С
жаемой строки обратную косую черту
\ .
·
218 -
Описываемая возможность
особенно полезна для определения
“объявляемых констант”, как,
например,
#DEFINE TABSIZE 100
INT TABLE[TABSIZE];
Управляющая строка вида
#UNDEF идентификатор
приводит к отмене препроцессорного
определения данного иден-
тификатора.
20.2. Включение файлов
Строка управления
компилятором вида
#INCLUDE “FILENAME”
приводит к замене этой строки на
все содержимое файла с име-
нем FILENAME. Файл с этим именем
сначала ищется в справочни-
ке начального исходного файла, а
затем в последовательности
стандартных мест. В отличие от
этого управляющая строка вида
#INCLUDE <FILENAME>
ищет файл только в стандартных
местах и не просматривает
справочник исходного файла.
Строки #INCLUDE могут быть
вложенными.
20.3. Условная компиляция
Строка управления
компилятором вида
#IF константное выражение
проверяет, отлично ли от нуля
значение константного выраже-
ния (см. П. 15). Управляющая строка
вида
#IF DEF идентификатор
проверяет, определен ли этот
идентификатор в настоящий мо-
мент в препроцессоре, т.е.
Определен ли этот идентификатор с
помощью управляющей строки #DEFINE.
21. Неявные описания
Не всегда является
необходимым специфицировать и класс
памяти и тип идентификатора в
описании. Во внешних определе-
ниях и описаниях формальных
параметров и членов структур
класс памяти определяется по
контексту. Если в находящемся
внутри функции описании не указан
тип, а только класс памя-
ти, то предполагается, что идентификатор
имеет тип INT; если
не указан класс памяти, а только
тип, то идентификатор пред-
полагается описанным как AUTO.
Исключение из последнего пра-
вила дается для функций, потому что
спецификатор AUTO для
функций является бессмысленным
(язык “C” не в состоянии ком-
пилировать программу в стек); если
идентификатор имеет тип
“функция, возвращающая ...”, то он
предполагается неявно
описанным как EXTERN.
·
219 -
Входящий в выражение и
неописанный ранее идентификатор,
за которым следует скобка ( ,
считается описанным по контек-
сту как “функция, возвращающая
INT”.
22. Снова о типах
В этом разделе обобщаются
сведения об операциях, которые
можно применять только к
объектам определенных типов.
22.1. Структуры и объединения
Только две вещи можно
сделать со структурой или объеди-
нением: назвать один из их членов
(с помощью операции) или
извлечь их адрес ( с помощью
унарной операции &). Другие
операции, такие как присваивание им
или из них и передача их
в качестве параметров, приводят к
сообщению об ошибке. В бу-
дущем ожидается, что эти операции,
но не обязательно ка-
кие-либо другие, будут разрешены.
В п. 15.1 Говорится, что при
прямой или косвенной ссылке
на структуру (с помощью . Или
->) имя справа должно быть
членом структуры, названной или указанной
выражением слева.
Это ограничение не навязывается
строго компилятором, чтобы
дать возможность обойти правила
типов. В действительности
перед '.' допускается любое
L-значение и затем предполагает-
ся, что это L-значение имеет форму
структуры, для которой
стоящее справа имя является членом.
Таким же образом, от вы-
ражения, стоящего перед '->',
требуется только быть указате-
лем или целым. В случае указателя
предполагается, что он
указывает на структуру, для которой
стоящее справа имя явля-
ется членом. В случае целого оно
рассматривается как абсо-
лютный адрес соответствующей
структуры, заданный в единицах
машинной памяти.
Такие структуры не являются
переносимыми.
22.2. Функции
Только две вещи можно
сделать с функцией: вызвать ее или
извлечь ее адрес. Если имя функции
входит в выражение не в
позиции имени функции,
соответствующей обращению к ней, то
генерируется указатель на эту
функцию. Следовательно, чтобы
передать одну функцию другой, можно
написать
INT F();
...
G(F);
Тогда определение функции G
могло бы выглядеть так:
G(FUNCP)
INT(*FUNCP)();
\(
...
(*FUNCP)();
...
\)
Обратите внимание, что в вызывающей
процедуре функция F дол-
жна быть описана явно, потому что
за ее появлением в G(F) не
следует скобка ( .
·
220 -
22.3. Массивы, указатели
и индексация
Каждый раз, когда
идентификатор, имеющий тип массива,
появляется в выражении, он
преобразуется в указатель на пер-
вый член этого массива. Из-за этого
преобразования массивы
не являются L-значениями. По
определению операция индексация
[] интерпретируется таким образом,
что E1[E2] считается
идентичным выражению *((е1)+(е2)).
Согласно правилам преоб-
разований, применяемым при операции
+, если E1 - массив, а
е2 - целое, то е1[е2] ссылается на
е2-й член массива е1. По-
этому несмотря на несимметричный
вид операция индексации яв-
ляется коммутативной.
В случае многомерных массивов
применяется последователь-
ное правило. Если е является
N-мерным массивом размера
I*J*...*K, то при появлении в
выражении е преобразуется в
указатель на (N-1)-мерный массив
размера J*...*K. Если опе-
рация * либо явно, либо неявно, как
результат индексации,
применяется к этому указателю, то
результатом операции будет
указанный (N-1)-мерный массив,
который сам немедленно преоб-
разуется в указатель.
Рассмотрим, например, описание
INT X[3][5];
Здесь X массив целых размера 3*5.
При появлении в выражении
X преобразуется в указатель на
первый из трех массивов из 5
целых. В выражении X[I], которое
эквивалентно *(X+I), снача-
ла X преобразуется в указатель так,
как описано выше; затем
I преобразуется к типу X, что
вызывает умножение I на длину
объекта, на который указывает
указатель, а именно на 5 целых
объектов. Результаты складываются,
и применение косвенной
адресации дает массив (из 5 целых),
который в свою очередь
преобразуется в указатель на первое
из этих целых. Если в
выражение входит и другой индекс,
то таже самая аргументация
применяется снова; результатом на
этот раз будет целое.
Из всего этого следует, что
массивы в языке “C” хранятся
построчно ( последний индекс
изменяется быстрее всего) и что
первый индекс в описании помогает
определить общее количест-
во памяти, требуемое для хранения
массива, но не играет ни-
какой другой роли в вычислениях,
связанных с индексацией.
22.4. Явные преобразования
указателей
Разрешаются определенные
преобразования, с использовани-
ем указателей , но они имеют
некоторые зависящие от конкрет-
ной реализации аспекты. Все эти
преобразования задаются с
помощью операции явного
преобразования типа; см. П. 15.2 и
16.7.
Указатель может быть
преобразован в любой из целочислен-
ных типов, достаточно большой для
его хранения. Требуется ли
при этом INT или LONG, зависит от
конкретной машины. Преоб-
разующая функция также является
машинно-зависимой, но она
будет вполне естественной для тех,
кто знает структуру адре-
сации в машине. Детали для
некоторых конкретных машин приво-
дятся ниже.
Объект целочисленного типа
может быть явным образом пре-
образован в указатель. такое
преобразование всегда переводит
преобразованное из указателя целое
в тот же самый указатель,
но в других случаях оно будет
машинно-зависимым.
·
221 -
Указатель на один тип может
быть преобразован в указа-
тель на другой тип. Если
преобразуемый указатель не указыва-
ет на объекты, которые подходящим
образом выравнены в памя-
ти, то результирующий указатель
может при использовании вы-
зывать ошибки адресации.
Гарантируется, что указатель на
объект заданного размера может быть
преобразован в указатель
на объект меньшего размера и снова
обратно, не претерпев при
этом изменения.
Например, процедура
распределения памяти могла бы прини-
мать запрос на размер выделяемого
объекта в байтах, а возв-
ращать указатель на символы; это
можно было бы использовать
следующим образом.
EXTERN CHAR *ALLOC();
DOUBLE *DP;
DP=(DOUBLE*)
ALLOC(SIZEOF(DOUBLE));
*DP=22.0/7.0;
Функция ALLOC должна обеспечивать
(машинно-зависимым спосо-
бом), что возвращаемое ею значение
будет подходящим для пре-
образования в указатель на DOUBLE;
в таком случае использо-
вание этой функции будет переносимым.
Представление указателя на
PDP-11 соответствует 16-бито-
вому целому и измеряется в байтах.
Объекты типа CHAR не име-
ют никаких ограничений на
выравнивание; все остальные объек-
ты должны иметь четные адреса.
На HONEYWELL 6000 указатель
соответствует 36-битовому
целому; слову соответствует 18
левых битов и два непосредст-
венно примыкающих к ним справа
бита, которые выделяют символ
в слове. Таким образом, указатели
на символы измеряются в
единицах 2 в степени 16 байтов; все
остальное измеряется в
единицах 2 в степени 18 машинных
слов. Величины типа DOUBLE
и содержащие их агрегаты должны
выравниваться по четным ад-
ресам слов (0 по модулю 2 в степени
19). Эвм IBM 370 и
INTERDATA 8/32 сходны между собой.
На обеих машинах адреса
измеряются в байтах; элементарные
объекты должны быть выров-
нены по границе, равной их длине,
так что указатели на SHORT
должны быть кратны двум, на INT и
FLOAT - четырем и на
DOUBLE - восьми. Агрегаты
выравниваются по самой строгой
границе, требуемой каким-либо из их
элементов.
23. Константные выражения
В нескольких местах в
языке “C” требуются выражения, ко-
торые после вычисления становятся
константами: после вариан-
тного префикса CASE, в качестве
границ массивов и в инициа-
лизаторах. В первых двух случаях
выражение может содержать
только целые константы, символьные
константы и выражения
SIZEOF, возможно связанные либо
бинарными операциями
+ - * / . % & \! Ч <<
>> == 1= <> <= >=
либо унарными операциями
- \^
либо тернарной операцией ?:
·
222 -
Круглые скобки могут использоваться
для группировки, но не
для обращения к функциям.
В случае инициализаторов допускается
большая (ударение
на букву о) свобода; кроме
перечисленных выше константных
выражений можно также применять
унарную операцию & к внешним
или статическим объектам и к
внешним или статическим масси-
вам, имеющим в качестве индексов
константное выражение.
Унарная операция & может быть
также применена неявно, в ре-
зультате появления
неиндексированных массивов и функций. Ос-
новное правило заключается в том,
что после вычисления ини-
циализатор должен становится либо
константой, либо адресом
ранее описанного внешнего или
статического объекта плюс или
минус константа.
24. Соображения о переносимости
Некоторые части языка “C”
по своей сути машинно-зависи-
мы. Следующие ниже перечисление
потенциальных трудностей хо-
тя и не являются всеобъемлющими, но
выделяет основные из
них.
Как показала практика,
вопросы, целиком связанные с ап-
паратным оборудованием, такие как
размер слова, свойства
плавающей арифметики и целого
деления, не представляют осо-
бенных затруднений. Другие аспекты
аппаратных средств нахо-
дят свое отражение в различных
реализациях. Некоторые из
них, в частности, знаковое
расширение (преобразующее отрица-
тельный символ в отрицательное
целое) и порядок, в котором
помещаются байты в слове,
представляют собой неприятность,
которая должна тщательно
отслеживаться. Большинство из ос-
тальных проблем этого типа не
вызывает сколько-нибудь значи-
тельных затруднений.
Число переменных типа
REGISTER, которое фактически может
быть помещено в регистры, меняется
от машины к машине, также
как и набор допустимых для них
типов. Тем не менее все ком-
пиляторы на своих машинах работают
надлежащим образом; лиш-
ние или недопустимые регистровые
описания игнорируются.
Некоторые трудности возникают
только при использовании
сомнительной практики
программирования. Писать программы,
которые зависят от каких- либо этих
свойств, является чрез-
вычайно неразумным.
Языком не указывается порядок
вычисления аргументов фун-
кций; они вычисляются справа налево
на PDP-11 и VAX-11 и
слева направо на остальных машинах.
порядок, в котором про-
исходят побочные эффекты, также не
специфицируется.
Так как символьные константы в
действительности являются
объектами типа INT, допускается
использование символьных
констант, состоящих из нескольких
символов. Однако, посколь-
ку порядок, в котором символы
приписываются к слову, меняет-
ся от машины к машине, конкретная
реализация оказывается
весьма машинно-зависимой.
Присваивание полей к словам и
символов к целым осуществ-
ляется справо налево на PDP-11 и
VAX-11 и слева направо на
других машинах. эти различия
незаметны для изолированных
программ, в которых не разрешено
смешивать типы (преобразуя,
например, указатель на INT в указатель
на CHAR и затем про-
веряя указываемую память), но
должны учитываться при согла-
совании с накладываемыми извне
схемами памяти.
·
223 -
Язык, принятый на различных
компиляторах, отличается
только незначительными деталями.
Самое заметное отличие сос-
тоит в том, что используемый в
настоящее время компилятор на
PDP-11 не инициализирует структуры,
которые содержат поля
битов, и не допускает некоторые
операции присваивания в оп-
ределенных контекстах, связанных с
использованием значения
присваивания.
25. Анахронизмы
Так как язык “C” является
развивающимся языком, в старых
программах можно встретить
некоторые устаревшие конструкции.
Хотя большинство версий компилятора
поддерживает такие анах-
ронизмы, они в конце концов
исчезнут, оставив за собой толь-
ко проблемы переносимости.
В ранних версиях “C” для
проблем присваивания использо-
валась форма =ON, а не ON=, приводя
к двусмысленностям, ти-
пичным примером которых является
X = -1
где X фактически уменьшается,
поскольку операции = и - при-
мыкают друг к другу, но что вполне
могло рассматриваться и
как присваивание -1 к X.
Синтаксис инициализаторов
изменился: раньше знак равенс-
тва, с которого начинается
инициализатор, отсутствовал, так
что вместо
INT X = 1;
использовалось
INT X 1;
изменение было внесено из-за
инициализации
INT F (1+2)
которая достаточно сильно
напоминает определение функции,
чтобы смутить компиляторы.
26. Сводка синтаксических правил
Эта сводка синтаксиса языка “C”
предназначена скорее для
облегчения понимания и не
является точной формулировкой язы-
ка.
26.1. Выражения Основными
выражениями являются следующие:
выражение:
первичное-выражение
·
выражение
& выражение
·
выражение
! Выражение
\^ выражение
++ L-значение
·
L-значение
L-значение ++
L-значение—
·
224 -
SIZEOF выражение
(имя типа) выражение
выражение бинарная-операция
выражение
выражение ? Выражение : выражение
L-значение операция-присваивания
выражение
выражение , выражение
первичное выражение:
идентификатор
константа
строка
(выражение)
первичное-выражение (список
выражений
необ)
первичное-выражение [выражение]
L-значение . Идентификатор
первичное выражение ->
идентификатор
L-значение:
идентификатор
первичное-выражение [выражение]
L-значение . Идентификатор
первичное-выражение ->
идентификатор
·
выражение
(L-значение)
Операции первичных выражений
() [] .
->
имеют самый высокий приоритет
и группируются слева
направо. Унарные операции
·
& - ! \^ ++ -- SIZEOF(Имя типа)
имеют более низкий приоритет, чем
операции первичных выраже-
ний, но более высокий, чем
приоритет любой бинарной опера-
ции. Эти операции группируются
справа налево. Все бинарные
операции и условная операция (прим.
Перевод.: условная опе-
рация группируется справа налево;
это изменение внесено в
язык в 1978 г.) группируются слева
направо и их приоритет
убывает в следующем порядке:
Бинарные операции:
* /
%
+ -
>> <<
<
> <= >=
== !=
&
\^
\!
&&
\!\!
?:
·
225 -
Все операции присваивания имеют
одинаковый приоритет и груп-
пируются справа налево.
Операции присваивания:
= += -=
*= ?= %= >>= <<= &= \^= \!=
Операция запятая имеет самый низкий
приоритет и группируется
слева направо.
26.2. Описания Описание:
спецификаторы-описания
список-инициализируемых-описателей
необ;
спецификаторы-описания:
спецификатор-типа спецификаторы-описания
необ
спецификатор-класса-памяти
спецификаторы-описания
необ
спецификатор-класса-памяти:
AUTO
STATIC
EXTERN
REGISTER
TYPEDEF
спецификатор-типа:
CHAR
SHORT
INT
LONG
UNSIGNED
FLOAT
DOUBLE
спецификатор-структуры-или-объединения
определяющее-тип-имя
список-инициализируемых-описателей:
инициализируемый-описатель
инициализируемый-описатель,
список-инициализируемых-описателей
инициализируемый-описатель
описатель-инициализатор
необ
описатель:
идентификатор
(описатель)
·
описатель описатель () описатель [константное выражение
необ]
·
226 -
спецификатор-структуры-или-объединения:
STRUCT список-описателей-структуры
STRUCT идентификатор
\(список-описаний-структуры\)
STRUCT идентификатор
UNION
\(список-описаний-структуры\)
UNION идентификатор
\(список-описаний-структуры\)
UNION идентификатор
список-описаний-структцры:
описание-структуры
описание-структуры список-описаний-структуры
описание структуры:
спецификатор-типа
список-описателей-структуры:
список-описателей-структуры
описатель-структуры
описатель-структуры,список-описателей-структуры
описатель-структуры:
описатель
описатель: константное выражение
:константное-выражение
инициализатор:
= выражение
= \(список-инициализатора\)
= \(список-инициализатора\)
список инициализатора:
выражение
список-инициализатора,список-инициализатора
\(список-инициализатора\)
имя-типа:
спецификатор-типа
абстрактный-описатель
абстрактный-описатель:
пусто
\(абстрактный-описатель\)
·
абстрактный-описатель абстрактный-описатель ()
абстрактный-описатель [константное-выражение
необ]
определяющее-тип-имя:
идентификатор
26.3. Операторы
составной-оператор:
\(список-описаний список-операторов
необ необ\)
список-описаний:
описание
описание список-описаний
список-операторов:
оператор
оператор список-операторов
оператор:
составной оператор
выражение;
·
227 -
IF (выражение) оператор
IF (выражение) оператор ELSE оператор
WHILE (выражение) оператор
DO оператор WHILE (выражение);
FOR(выражение-1 ;выражение-2 ;выражение-3 )
необ необ необ
оператор
SWITCH (выражение) оператор
CASE константное-выражение :
оператор
DEFAULT: оператор
BREAK;
CONTINUE;
RETURN;
RETURN выражение;
GOTO идентификатор;
идентификатор : оператор
;
26.4. Внешние определения
Программа:
внешнее-определение
внешнее-определение программа
внешнее-определение:
определение-функции
определение-данных
определение-функции:
спецификатор-типа описатель-функции
тело-функции
необ
описатель-функции:
описатель (список-параметров )
необ
список-параметров:
идетификатор
идентификатор , список-параметров
тело-функции:
список-описаний-типа
оператор-функции
оператор-функции:
\(список описаний
список-операторов\)
необ
определение данных:
EXTERN
спецификатор типа список
необ
необ
инициализируемых описателей ;
необ
STATIC
спецификатор типа список
необ
необ
инициализируемых описателей
необ;
26.5. Препроцессор
#DEFINE идентификатор строка-лексем #DEFINE
·
229 -
#DEFINE
идентификатор(идентификатор,...,идентификатор)стр
#UNDEF идентификатор
#INCLUDE “имя-файла”
#INCLUDE <имя-файла>
#IF константное-выражение
#IFDEF идентификатор
#IFNDEF идентификатор
#ELSE
#ENDIF
#LINE константа идентификатор
Последние изменения языка “C”
(15 ноября 1978 г.)
27. Присваивание структуры
Структуры могут быть
присвоены, переданы функциям в ка-
честве аргументов и возвращены
функциям. Типы участвующих
операндов должны оставаться теми же
самыми. Другие правдопо-
добные операторы, такие как
сравнение на равенство, не были
реализованы.
В реализации возвращения
структур функциями на PDP-11
имеется коварный дефект: если во
время возврата происходит
прерывание и та же самая функция
пеентерабельно вызывается
во время этого прерывания, то
значение возвращаемое из пер-
вого вызова, может быть испорчено.
Эта трудность может воз-
никнуть только при наличии
истинного прерывания, как из опе-
рационной системы, так и из
программы пользователя, прерыва-
ния, которое существенно для
использования сигналов; обычные
рекурсивные вызовы совершенно
безопасны.
28. Тип перечисления
Введен новый тип
данных,аналогичный скалярным типам язы-
ка паскаль. К спецификатору-типа в
его синтаксическом описа-
нии в разделе 8.2. Приложения а
следует добавить
спецификатор-перечисления
с синтаксисом
пецификатор-перечисления:
ENUM
список-перечисления
ENUM идентификатор
список-перечисления
------------- -------------------
ENUM
идентификатор
·
230 -
cписок-перечисления:
перечисляемое
список-перечисления,
перечисляемое
-------------------
-------------
перечисляемое:
идентификатор
идентификатор = константное
выражение
------------- ---------------------
Роль идентификатора в
спецификаторе-перечисления пол-
ностью аналогична роли ярлыка
структуры в спецификато-
ре-структуры; идентификатор
обозначает определенное перечис-
ление. Например, описание
ENUM COLOR \(RED, WHITE, BLACK,
BLUE \);
. . .
ENUM COLOR *CP, COL;
Объявляет идентификатор COLOR
ярлыком перечисления типа,
описывающего различные цвета и
затем объявляет CP указателем
на объект этого типа, а COL -
объектом этого типа.
Идентификаторы в
списке-перечисления описываются как
константы и могут появиться там,
где требуются (по контекс-
ту) константы. Если не используется
вторая форма перечисляе-
мого (с равеством =), то величины
констант начинаются с 0 и
возрастают на 1 в соответствии с
прочтением их описания сле-
ва на право. Перечисляемое с
присвоением = придает соответс-
твующему идентификатору указанную
величину; последующие
идентификаторы продолжают
прогрессию от приписанной величи-
ны.
Все ярлыки перечисления и
константы могут быть различны-
ми и непохожими на ярлыки и
члены структур даже при условии
использования одного и того же
множества идентификаторов.
Объекты данного типа
перечисления рассматриваются как
объекты, имеющие тип, отличный от
любых типов и контролирую-
щая программа LINT сообщает об
ошибках несоответствия типов.
В реализации на PDP-11 со всеми
перечисляемыми переменными
оперируют так, как если бы они
имели тип INT.
29. Таблица изображений непечатных
символов языка “C”.
В данной таблице приведены
изображения некоторых симво-
лов (фигурные скобки и т.д.) языка
“C”, которых может не
оказаться в знаковом наборе дисплея
или печатающего устройс-
тва.
·
231 -
!
Значение ! Изображение ** !
! ! В тексте !
! Фигурная
открывающаяся ! !
!
Скобка ! \( !
! ! !
! Фигурная
закрывающаяся ! !
!
Скобка ! \) !
! ! !
!
Вертикальная ! !
!
Черта ! \! !
! ! !
!
! !
!
Апостороф ! \' !
! ! !
!
Волнистая ! !
!
Черта ! \^ !
! ! !
** П_р_и_м_е_ч_а_н_и_е:
Изображения приведены для
операционой системы UNIX. При
работе компилятора “C” под
управлением любой другой операци-
онной системы, необходимо
воспользоваться соответствующим
руководством для данной системы.
|