Неявные описания
Не всегда необходимо специфицировать и класс памяти итип идентификатора в описании. Во внешних определениях иописаниях формальных параметров и членов структур класспамяти определяется по контексту. Если в находящемся внутрифункции описании не указан тип, а только класс памяти, топредполагается, что идентификатор имеет тип int; если неуказан класс памяти, а только тип, то идентификатор предпо-лагается описанным как auto. Исключение из последнего пра-вила дается для функций, потому что спецификатор auto дляфункций является бессмысленным (язык Си не в состоянии ком-пилировать программу в стек); если идентификатор имеет тип функция, возвращающая..., то он предполагается неявно опи-санным как extern. Входящий в выражение и неописанный ранее идентификатор,за которым следует скобка (, считается описанным по -42- контексту как функция, возвращающая int. /* extern */ int tab [100]; static /* int */ t1; /* int */ func (i) /* int i; */ { register /* int */ k; /* auto */ char buf [512]; /* extern int f1 (); */... f1 (a, b)...* 9. ПРЕПРОЦЕССОР ЯЗЫКА 'СИ'
Компилятор языка Си содержит препроцессор, который поз-воляет осуществлять макроподстановки, условную компиляцию ивключение именованных файлов. Строки, начинающиеся с #,являются командами этого препроцессорa. Синтаксис этих строкне связан с остальным языком; они могут появляться в любомместе и их влияние распространяется (независимо от областидействия) до конца исходного программного файла. Фактическипрепроцессор расширяет возможности языка Си, реализуя такиефункции, которые в других языках входят в состав самогоязыка (например, параметрические константы в Фортране-77).Замена лексем
Команда #define идентификатор строка _ лексем (обратите внимание на отсутствие в конце точки с запятой)приводит к тому, что препроцессор заменяет последующие вхож-дения этого идентификатора на указанную строку лексем.Строка вида #define идентификатор (идентифика - тор,..., идентификатор) строка _ лексем где между первым идентификатором и открывающейся скобкой "("нет пробела, представляет собой макроопределение с аргумен-тами. В дальнейшем первый идентификатор, за которым следуетоткрывающая скобка "(", последовательность разделенных запя-тыми лексем и закрывающая скобка ")", заменяются строкойлексем из определения. Каждое вхождение идентификатора, упо-мянутого в списке формальных параметров в определении, заме-няется соответствующей строкой лексем из обращения. Факти-ческими аргументами в обращении являются строки лексем, раз-деленные запятыми; однако запятые, входящие в закавыченныестроки или заключенные в круглые скобки, не разделяют аргу-ментов. Количество формальных и фактических параметровдолжно совпадать. Текст внутри строки или символьной конс-танты не подлежит замене. -43- В обоих случаях замененная строка просматривается сновас целью обнаружения других идентификаторов, известных преп-роцессору. В обоих случаях слишком длинная строка определе-ния может быть продолжена на другой строке, если поместить вконце продолжаемой строки обратную косую черту " \ ". Описываемая возможность особенно полезна для определе-ния "объявляемых констант", как, например, #define TABSIZE 100 int table [TABSIZE]; или для замены некоторых функций с помощью макроподстановки: #define max (a, b) ((a)>(b)?(a):(b)) x = max (y,20) (в последнем определении a и b взяты в скобки, для того,чтобы фактическими параметрами макро могли бы быть произ-вольные выражения. Команда #undef идентификатор приводит к отмене препроцессорного определения данного иден-тификатора. Определить идентификатор можно не только с помощьюкоманды #define, но также и при вызове компилятора, спомощью параметров команды cc.Включение файлов
Команда #include " filename " приводит к замене этой строки на все содержимое файла с име-нем filename. Файл с этим именем сначала ищется в текущемсправочнике, а затем в других "стандартных" местах, опреде-ляемых пользователем при вызове компилятора. В отличие отэтого команда #include < filename > ищет файл только в стандартном справочнике системы. В ОС ДЕМОС файл ищется в справочнике / usr / include. Команды #include могут быть вложенными. -44-Условная компиляция
Команда препроцессора #if константное выражение проверяет, отлично ли от нуля значение константного выраже-ния. Команда: #ifdef идентификатор проверяет, определен ли этот идентификатор в настоящиймомент в препроцессоре, т.е. определен ли этот идентификаторс помощью команды #define. Команда: #ifndef идентификатор проверяет, является ли этот идентификатор в данный момент неопределенным для препроцессора. За каждым из трех перечисленных видов строк может сле-довать произвольное число строк, возможно содержащих командупрепроцессора #else а затем должна следовать команда: #endif Если проверяемое условие истинно, то любые строки между #else и #endif игнорируются. Если проверяемое условие ложно,то любые строки между проверяемой строкой и #else или, приотсутствии #else, #endif игнорируются. Эти конструкции могут быть вложенными. Например: #ifdef DEBUG fprintf (stderr," i =% o j =% d\n ", i, j); #endif Переменная препроцессора может быть определена не только всамой программе, но и при вызове транслятора.Команда #line
Для других препроцессоров, генерирующих Си-программы,полезна следующая команда: #line константа "имя _ файла " -45- которая сообщает компилятору (для диагностических сообще-ний), что следующая строка исходного файла имеет номер,задаваемый константой, и что текущий входной файл именуется именем _ файла. Если имя _ файла отсутствует, то запоминаемоеимя файла не изменяется. Пример: #line 250 " gram. y "* 10. ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ О ТИПАХ
В этом разделе обобщаются сведения об операциях, кото-рые можно применять только к объектам определенных типов.





