ТОР 5 статей: Методические подходы к анализу финансового состояния предприятия Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века Характеристика шлифовальных кругов и ее маркировка Служебные части речи. Предлог. Союз. Частицы КАТЕГОРИИ:
|
ДИРЕКТИВЫ ПРЕПРОЦЕССОРА
Препроцессор - это программа, которая производит некоторые, иногда весьма значительные, манипуляции с первоначальным текстом программы перед тем, как он подвергается трансляции. Оператор препроцессора - это одна строка исходного текста, начинающаяся с символа #, за которым следуют название оператора и операнды. Операторы препроцессора могут появляться в любом месте программыи их действие распространяется на весь исходный файл. Весьма часто используют следующие операторыпрепроцессора:
#include #define
Более специфичными являются директивы #pragma, #if, #error и др. Важная возможность препроцессора - включение в исходный текст содержимого других файлов. Эта возможность, в основном, используется для того, чтобы снабжать программы какими-то общими для всех данными, определениями. Например, чрезвычайно часто в начале программы на языке Си встречается препроцессорная конструкция
#include <stdio.h>
Когда исходный текст программы обрабатывается препроцессором, на место этой инструкции ставится содержимое расположенного в некоем стандартном месте файла stdio.h, содержащего макроопределения и объявления данных, необходимых для работы функций из стандартной библиотеки ввода-вывода. Для использования различных математических функций необходимо подключать файл описаний math.h. Функции, оперирующие со строками, описаны в файле string.h, функции общего назначения - в stdlib.h, функции даты и времени - в time.h, диагностика - в assert, h и т.д. Директива #define позволяет дать в программе макроопределения (или задать макросы). Оператор макроопределения имеет вид
#define <макроимя> <строка лексем> или #define <макроимя(<список параметров>)> <строка лексем>
Макроимя - это идентификатор. Строка лексем - это последовательность лексем от Макроимени до конца строки. Точка с запятой в конце макроопределения не ставится. Препроцессорная обработка макроопределения сводится к тому, что любое появление Макроимени (макровызов) в качестве отдельной лексемы в тексте программы, расположенном после макроопределения, ведет к замене этого Макроимени на указанную Строку лексем. Например, прочитав определения
#defmePI3.14159 #defineE2.711828
препроцессор заменит в программе все имена PI и Е на соответствующие числовые константы. Препроцессор языка Си позволяет переопределять не только константы, но и целые программные конструкции. Например, можно написать определение
#define forever for(;;)
и затем всюду писать бесконечные циклы в виде forever Определение макроимени с параметрами имеет некоторую специфику. Список параметров макроимени - это список идентификаторов, разделенных запятыми. Следующая после списка параметров строка лексем также может содержать эти параметры, которые при макровызове будут заменены на соответствующие аргументы. Макровызов должен быть отдельной лексемой и состоять из макроимени и заключенного в круглые скобки списка аргументов. При обработке макровызова препроцессор заменяет каждый параметр в строке лексем на соответствующий аргумент макровызова. В следующих программах иллюстрируются некоторые применения операторов препроцессора. Пример 1: найти большее из двух чисел.
Программа 110 #include<stdio.h> #define MAX(X,Y) ((X)>(Y)? (X): (Y)) main() { int x,y; scanf ("%d %d", &x, &y); printf ("%d", MAX(x, y)); ) Результат работы программы: 3 5 Пример 2. Программа 111
#include<stdio.h> #define S (x) x*x #define P(x) printf("x равен %d.\n",x) main() { int x=4; int z; z = S(x); P(z); z = 3(2); P(z); P(S(x)); P(S(x+2)); P(100/S(2)); P(S(++x)); } Результат работы программы:
x равен16. x равен 4. x равен 16. x равен 14. x равен 100. x равен 30.
Оператор препроцессора #pragma позволяет записывать самые различные указания компилятору (зависящие от конкретного компилятора). Например, следующие два предложения препроцессора
#pragma recursive #pragma nonrec
устанавливают режим всех функций программы по умолчанию рекурсивным или нерекурсивным. Указание препроцессора
#pragma optimize time
воспринимается компилятором таким образом, что он старается сгенерировать объектный код, отличающийся более высокой скоростью выполнения, чем в случае, когда он должен быть более компактным.
СИ И ПАСКАЛЬ
При знакомстве с языком Си, особенно после изучения Паскаля и Бейсика, погружение в детали его изобразительных средств может затушевать важную мысль: хотя на Си можно написать практически любую прикладную программу, он изначально для этого не предназначен. Си является результатом эволюционного развития языков создания системных программных средств. Если в прикладном программировании эволюция шла от Фортрана к Алголу, Коболу, Паскалю и т.д., то в системном - от Ассемблеров, привязанных к архитектуре ЭВМ, к Си, для которого созданы трансляторы, делающие его хоть и независимым от архитектуры, но не меняющим основного предназначения. С помощью Си можно сделать то, что на Паскале сделать невозможно (или почти невозможно) - например, написать фрагмент операционной системы (или новую операционную систему), утилиты и т.п. Так, ряд трансляторов с Паскаля написаны на Си; обратное невозможно представить. В то же время, не раз отмечалось, что прикладные программы, написанные на Паскале, отличаются большей надежностью, чем написанные на Си; их легче читать, передавать от одного программиста другому для совершенствования и сопровождения. Это связано с тем, что Паскаль содержит существенно больше ограничений и является языком более высокого уровня с сильной типизацией данных. Для языка же. который предназначен для разработки системного программного обеспечения, чем меньше ограничений, тем лучше; так, в Си возможны неявные преобразования всех базовых типов данных и указателей друг в друга, что крайне желательно при создании системных средств, но при невнимательности программиста приводит к ошибкам, не улавливаемым транслятором с Си (Паскаль же подобные недопустимые операции пресекает немедленно). Разумеется, сказанное выше не следует абсолютизировать. Программисты, привыкшие к Си, успешно пишут на нем программы различных классов. Это касается не только Си - вспомните об экспертных системах, написанных на Бейсике. В то же время, при массовом программировании придерживаться «разделения труда» между языками представляется более естественным.
Контрольные вопросы и задания
1. Охарактеризуйте назначение и особенности языка Си. 2. Какие символы образуют алфавит языка Си? 3. Что называется лексемами, идентификаторами, литералами? Приведите примеры. 4. Какие типы данных используются в Си? Приведите примеры описания переменных. 5. Охарактеризуйте арифметические, логические и битовые операции Си. 6. Какие разновидности оператора присваивания имеются в Си? 7. Как на языке Си можно описать ветвление? 8. Охарактеризуйте возможности цикла for. Приведите примеры. 9. Какие логические циклы имеются в Си? Приведите примеры их использования. 10. Какие операторы управления имеются в Си? 11. Какова структура программы на Си? Что такое функция? 12. Приведите примеры использования функций (с аргументами и без, возвращающих и не возвращающих значения). 13. Для чего в качестве аргументов функций используются указатели? Приведите примеры. 14. Для чего в Си существуют классы памяти? 15. Что такое потоки и файлы в Си? 16. Охарактеризуйте стандартные функции ввода и вывода в Си. 17. Что такое препроцессор Си? Приведите примеры директив препроцессора.
Не нашли, что искали? Воспользуйтесь поиском:
|