Директивы препроцессора
Директивы
препроцессора, по сути, не являются составной частью языка C, а используются для подстановки кода в текст программы.
Препроцессор — это особая программа, которая выполняет предварительную
обработку данных до начала компиляции. Рассмотрим стандартные директивы
препроцессора.
Директива
#include
Выше,
в разделе "Структуры программы на С" уже упоминалась самая распространенная
директива #include, которая используется фактически во всех программах
для включения в текст программы заголовочных файлов (c определениями), имеющий расширение .h, или файлов .c (не
содержащих функцию main () ). Эта директива
может использоваться в двух формах:
#include <имя_файла>
или
#include "имя_файла"
Если
имя файла заключено между знаками < и >, то он считается частью
стандартной библиотеки, поставляемой вместе с компилятором. Если же имя файла
заключено между знаками « и », то считается, что он расположен в той же папке,
что и файл с исходным кодом.
Директива
#define
Директива
#define указывает препроцессору на необходимость выполнить
подстановку, в тексте программы определенной последовательности символов другой
последовательностью. Формат директивы:
#define заменяемая_последовательность фрагмент_подстановки
Например:
#define MyName
"John Smith"
#define Condition
(a > b)
#define Operation
a = b
…
char str[ ]
= MyName; //Равнозначно
char str[ ] =
"John Smith";
int a,
b;
if Condition Operatrion; //Равнозначно if (a > b) a = b;
В
директиве #define могут использоваться параметры, благодаря чему она
становится очень мощным и гибким инструментом, позволяющим заменять один
простой текстовый элемент сложным выражением. Такие подстановки называют
макросами.
Например,
выражение, в котором выбирается большее из двух значений, можно представить в
виде следующего макроса.
#define larger(x,у) ((х) > (у) ? (х) : (у))
Если
определен такой макрос, то код, использующий его, может иметь следующий вид:
int a = 9;
int b = 7;
int с = 0;
с = larger(a,b);
Напоминает
вызов функции, однако это не функция — компилятор получит от препроцессора
последнюю строку в следующем виде.
с = ((а) >
(b) ? (а) : (b));
Основное
отличие макроса от функции заключается в том, что код макроподстановки
вставляется препроцессором в программный код везде, где встречается заданный
текстовый элемент, код же функции определяется только в одном месте, а в тех
местах, где указано ее имя, осуществляется вызов этого кода.
Есть
и еще одно отличие, особенно важное при программировании микроконтроллеров, —
при использовании макросов, в отличие от функций, ничего не помещается в стек,
что позволяет сэкономить оперативную память.
Кроме
того, макросы преобразуются в обычный код, который выполняется быстрее, чем код
функции, на вызов которого и возврат управления в вызывающую функцию уходит
дополнительное машинное время. Наконец, при использовании макросов не требуется
формального объявления типов данных.
Перечислим
некоторые правила использования директивы #define:
при создании комментариев в строке с #def ine всегда используется комментарий вида/* ...
*/;
следует помнить, что конец строки — это конец #define, и весь текст слева заменить текст справа;
для преобразования параметра макроса в текстовую
строку можно указать перед ним символ "#", например:
#define
OutString(s) puts(# s)
OutString(Line); //Равнозначно puts("Line");
для конкатенации двух параметров можно
воспользоваться оператором ##, например:
#define Concat(x, у) х ## у
int i =
Concat(2,1); //Равнозначно int i
= 21;
для переноса текста подстановки на другую строку
используется символ обратной косой "\", например:
#define LongStr "О
123456789 10 \
11 12 13 14
15 16 17 18 19 20 "
для отмены определения используется директива #undef, например:
#define
A_Char 'A'
…
#undef A_Char
#define A_Char 'a'.