Препроцессор языка Си
Мы уже
использовали некоторые возможности
препроцессора языка Си, сейчас поговорим о нем
более подробно. Препроцессор (макропроцессор)
- это составная часть стандартного пакета языка
Си, которая обрабатывает исходный текст
программы до того, как он пройдет через
компилятор. Препроцессор читает строки текста и
выполняет действия, определяемые командными
строками. Если первый отличный от пробела символ
в строке- управляющий (# ), то такая
строка рассматривается препроцессором как
командная. Строки, не являющиеся командными, либо
подвергаются преобразованиям, либо остаются без
изменения.
Рассиотрим наиболее часто используемые
возможности препроцессора: макрогенерация
(замена лексических единиц), включение файлов,
условная компиляция.
Замена
лексических единиц. Командная строка вида #define
name text вызывает в оставшейся части программы
замену всех вхождений идентификатора name на
строку text. Например, определение #define
p1 3.14159265 позволяет использовать в программе
имя p1 вместо константы 3.14159265. Обратите
внимание, что это определение не завершается
точкой с запятой. Замещающий текст обычно
представляет собою остаток строки. Длинное
определение можно продолжить, если в конце
продолжаемой строки поставить \. Внутри
строк, заключенных в кавычки, подстановка не
производится, так что, например, для
определенного выше имени P1 в printf("P1"); подстановки
не будет. Имена могут переопределяться и новые
определения могут использовать ранее введенные
определения.
Так как
препроцессор не является частью компилятора
языка Си, а представляет относительно простой
макрогенератор, имеется возможность
переопределять различные синтаксические
единицы языка-лексемы (т.е. идентификаторы,
ключевые слова, константы, цепочки литер, знаки
операций и знаки пунктуаций). В приведенной (на
примере 6.2) программе, предназначенной для
выявления всех пар целых чисел из интервала [-n,n],
являющихся решениями уравнения 2*y-x*x =4 , используются
привычные для таких языков как Алгол, Паскаль,
операторные скобки begin-end вместо пары {},
ключевое слово then . Это стало
возможным благодаря предварительно
определенным лексическим заменам.
Пример 6.2
#include <stdio.h>
#define then
#define begin {
#define end }
main()
begin
int n,x,y,k=0;
printf("введи n\n");scanf("%d",&n);
for(x=-n;x<=n;x++)
for(y=-n;y<=n;y++)
if(2*y-x*x==4)then
begin
k=k+1;
printf(x=%d, y=%d\n",x,y);
end
if(k==0) then
printf("корней нет\n ");
end |
Приведенная
выше технология замены лесксем относится к макросредствам
языка. Строка #define name text называется
макроопределением, name называется
макрошаблоном, а text - макрорасширением.
Каждое появление имени name в теле
программы называется макровызовом. Командная
строка
#define name (p1,p2, ..,pk) text
является
макроопределением с аргументами. За именем name
в круглых скобках (после name не
должно быть пробела!) следует разделенные
запятыми формальные параметры p1, p2 .., pk, также
являющиеся идентификаторами. Каждый раз, когда в
тексте программы встречается имя
макроопределения с фактичкскими аргументами,
они подставляются вместо формальных, так что
заменяющий текст будет зависеть от вида
макровызова. Определим в качестве примера такую
макроподстановку:
#define
MAX(X,Y) ((X)>(Y)?(X):(Y))
Как и в
определении функции, переменные X и Y
в макроопределении являются формальными
параметрами. После этого строка в программе:
m=MAX(a+b, a-b);
будет заменена
на строку
m=((a+b)>(a-b)?(a+b):(a-b);
Текст
макроопределения берут в скобки для обеспечения
большей надежности программы. Пренебрежение
скобками может привести к серьезным ошибкам, что
иллюстрирует следующий пример 6.3. делит число 16
на квадрат числа 2 и дает правильный
результат. Во второй программе (пример 6.4), где
скобки в макроопределении опущены, результат
ошибочный, так как макроподстановка породила
текст:
printf("%d\n",16/2*2);
что конечно, не
равносильно задуманному.
Пример 6.3
#include <stdio.h>
#define SQR(n) (n*n)
main()
{
printf("%d\n",16/SQR(2));
} |
Пример 6.4
#include <stdio.h>
#define SQR(n) n*n
main()
{
printf("%d\n",16/SQR(2));
} |
Макроопределения
иногда используются вместо определений функций,
обычно из сображений эффективности. Но следует
помнить, что препроцесор может лишь тупо и
бездумно заменять одну строку на другую, не
разбираясь, зачем это нужно. В отличае от
параметра функции, параметр макроопределения
вычисляется при каждом вхождении в
макроопределение. Поэтому иакровызов MAX(i++,
j++) для приведенного выше
макроопределения к увеличению i и j на
2.
< Дальше >
|