Вівторок, 19.03.2024, 08:16
Гость

Мішатронік

Мобільна версія | Додати у вибране  | Мій профіль | Вихід | RSS |
Меню сайту
Наше опитування
Чи працювали ви з мікроконтролером?
Всього відповідей: 5
Статистика

Онлайн всього: 1
Гостей: 1
Користувачів: 0


Общие сведения

В интегрированную среду подготовки программ на Си или в компилятор языка как обязательный компонент входит препроцессор. Назначение препроцессора - обработка исходного текста программы до ее компиляции. Препроцессорная обработка включает несколько стадий, выполняемых последовательно. Конкретная реализация может объединять несколько стадий, но результат должен быть таким, как если бы они выполнялись в следующем порядке:

 
  1. Все системно-зависимые обозначения перекодируются в стандартные коды.
  2. Каждая пара из символов ' \ ' и "конец строки" вместе с пробелами между ними убираются, и тем самым следующая строка исходного текста присоединяется к строке, в которой находилась эта пара символов.
  3. В тексте распознаются директивы и лексемы препроцессора, а каждый комментарий заменяется одним символом пустого промежутка.
  4. Выполняются директивы препроцессора и производятся макроподстановки.
  5. Эскейп-последовательности в символьных константах и символьных строках заменяются на их эквиваленты.
  6. Смежные символьные строки конкатенируются, то есть соединяются в одну строку.
  7. Каждая препроцессорная лексема преобразуется в текст на языке Си.
 

Поясним, что понимается под препроцессорными лексемами или лексемами препроцессора. К ним относятся символьныеконстанты, имена включаемых файлов, идентификаторы, знаки операций, препроцессорные числа, знаки препинания, строковыеконстанты и любые символы, отличные от пробела.

 

Стадия обработки директив препроцессора. При ее выполнении возможны следующие действия:

 
  • замена идентификаторов заранее подготовленными последовательностями символов;
  • включение в программу текстов из указанных файлов;
  • исключение из программы отдельных частей ее текста, условная компиляция;
  • макроподстановка, то есть замена обозначения параметризованным текстом, формируемым препроцессором с учетом конкретных аргументов.
 

Символические константы: #define

Если в качестве первого символа в строке программы используется символ #, то эта строка является командной строкойпрепроцессора (макропроцессора). Командная строка препроцессора заканчивается символом перевода на новую строку. Если непосредственно перед концом строки поставить символ обратной косой черты " \ ", то командная строка будет продолжена на следующую строку программы.

 

Директива #define, подобно всем директивам препроцессора, начинается c символа # в самой левой позиции. Она может появиться в любом месте исходного файла, а даваемое определение имеет силу от места появления до конца файла. Мы активно используем эту директиву для определения символических констант в наших примерах программ, однако она имеет более широкое применение, что мы покажем дальше.

 

Замена идентификаторов

#define идентификатор строка
 

Пример:

 
#define ABC 100
 

Заменяет каждое вхождение идентификатора ABC в тексте программы на 100:

 
#undef идентификатор
 

Пример:

 
#undef ABC
 

Отменяет предыдущее определение для идентификатора ABC.

 

Пример:

 
/* Простые примеры директивы препроцессора */
#define TWO 2 /* можно использовать комментарии*/
#define MSG "Текст 1.\
Продолжение текста 1"
/* обратная косая черта продолжает определение на следующую строку */
#define FOUR TWO*TWO
#define PX printf("X равен %d.\n", x)
#define FMT "X равен %d.\n"
int main( )
{
 int x = TWO;
 PX;
 x = FOUR;
 printf(FMT,x);
 printf("%s\n",MSG);
 printf("TWO:MSG\n");
 return TWO;
}
 

В результате выполнения нашего примера будем иметь:

 
X равен 2
X равен 4
Текст 1. Продолжение текста 1
TWO: MSG
 

Разберем, что произошло. Оператор

 
int x = TWO;
 

превращается в

 
int x = 2;
 

Затем оператор

 
PX;
 

превращается в

 
printf("X равно %d.\n",x);
 

поскольку сделана полная замена. Теперь мы видим, что макроопределение может представлять любую строку, даже целое выражение на языке Си. Заметим, что это константная строка. PX напечатает только переменную, названную x.

В следующей строке выполняется следующее:

 
x = FOUR;
 

превращается

 
x = TWO*TWO;
 

превращается в

 
x = 2*2;
 

и на этом все заканчивается. Фактическое умножение имеет место не во время работы препроцессора и не при компиляции, а всегда без исключения при работе программы (Уточнение: это зависит от конкретного компилятора). Препроцессор не выполняет вычислений. Он только очень точно делает предложенные подстановки. Заметим, что макроопределение может включать другие определения. Некоторые компиляторы не поддерживают это свойство вложения. В следующей строке

 
printf(FMT,x);
 

превращается в

 
printf("X равно %d.\n",x)
 

когда FMT заменяется соответствующей строкой. Этот подход может оказаться очень удобным, если есть длинная строка, которую мы используем несколько раз. В следующей строке программы MSG заменяется соответствующей строкой. Кавычки делают замещающую строку константой символьной строки. Поскольку программа получает ее содержимое, эта строка будет запоминаться в массиве, заканчивающемся нуль-символом. Так,

 
#define HAL 'X' определяет символьную константу, а 
#define HAR "X" определяет строковую строку X\0
 

Обычно препроцессор, встречая одно из макроопределений в программе, очень точно заменяет их эквивалентной строкой замещения. Если эта строка также содержит макроопределения, они тоже замещаются. Единственным исключением при замене является макроопределение, находящееся внутри двойных кавычек. Поэтому

 
printf("TWO: MSG");
 

печатает буквально TWO: MSG вместо печати следующего текста:

 
2: "Текст 1.
Продолжение текста 1"
 

Если нам нужно напечатать этот текст, можно использовать оператор

 
printf("%d: %s\n",TWO,MSG);
 

потому что здесь макроопределения находятся вне кавычек.

 

Когда следует использовать символические константы? Вероятно, мы должны применять их для большинства чисел. Если число является константой, используемой в вычислениях, то символическое имя делает яснее ее смысл. Если число - размер массива, тосимволическое имя упрощает изменение вашей программы при работе с большим массивом. Если число является системным кодом, скажем для символа EOF, то символическое представление делает программу более переносимой. Изменяется только определениеEOF. Мнемоническое значение, легкость изменения, переносимость: все это делает символические константы заслуживающими внимания!

 

Форма входа
Пошук
Друзі сайту
Календар
«  Березень 2024  »
ПнВтСрЧтПтСбНд
    123
45678910
11121314151617
18192021222324
25262728293031

Єдина Країна! Единая Страна!