Препроцессор Си
Препроцессор C - это макропрепроцессор для языков программирования C, Objective-C и C++. Препроцессор автоматически запускается компилятором C перед компиляцией. Он называется макропроцессором, потому что позволяет определять макросы, которые являются сокращенными идентификаторами для более длинных конструкций.
Во многих реализациях языка Си это отдельная программа, вызываемая компилятором в качестве первой части трансляции. Таким образом, на вход компилятора попадает текст, который может отличаться от того, который видит программист. Символ # (перед которым возможны символы-разделители) является знаком для препроцессора. Синтаксис таких строк не зависит от грамматики C, они могут появляться где угодно и не зависят от области видимости. Иногда препроцессор Си используется также для обработки других видов текстовых файлов.
Препроцессор языка Си предоставляет четыре отдельные возможности, которые вы можете использовать по своему усмотрению:
- Включение заголовочных файлов. Это файлы с декларациями, которые могут быть вставлены в вашу программу.
- Развертка макросов. Вы можете создать макросы, которые являются сокращениями для произвольных фрагментов языка Си, а затем препроцессор Си заменит макросы их определениями во всей программе.
- Условная компиляция. Используя специальные директивы препроцессирования, вы можете включать или исключать части программы в соответствии с различными условиями.
- Контроль строк. Если вы используете препроцессор для объединения или перестановки исходных файлов в промежуточный файл, вы можете управлять порядком строк (используют кальку "порядок инклюдов"), и это в ряде случаев влияет на результат компиляции.
История
Препроцессор появился в языке Си в 1973 году в связи с признанием полезности механизмов включения файлов, доступных в BCPL. Его первоначальная версия предлагала только включение файлов и простую замену строк с помощью #include и #define для макросов без параметров, соответственно. Вскоре она была расширена для включения макросов с аргументами и условной компиляции.
Включение файлов
Одно из самых распространенных применений препроцессора - это включение другого файла:
#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 0;
}
Препроцессор заменяет строку #include <stdio.h> текстовым содержимым файла 'stdio.h', в котором, помимо прочего, объявлена функция printf().
В другом варианте синтаксиса используются двойные кавычки (например, #include "stdio.h"), это влияет на порядок поиска заголовка. Если имя файла заключено в угловые скобки, файл ищется в стандартных путях включения компилятора. Если имя файла заключено в двойные кавычки, то путь поиска расширяется и включает текущий каталог исходных файлов. Компиляторы языка Си и среды программирования имеют средства, позволяющие программисту определить, где можно найти включаемые файлы. Это может быть сделано с помощью флага командной строки, который может быть параметризован с помощью makefile, так что, например, для разных операционных систем может быть использован разный набор включаемых файлов.
По соглашению, включаемые файлы именуются с расширением .h или .hpp, но это не является обязательным требованием. Файлы с расширением .def могут обозначать файлы, предназначенные для многократного включения, каждый раз разворачиваясь в одно и то же повторяющееся содержимое; #include "icon.xbm", скорее всего, включает файл изображения XBM (который в то же время является исходным файлом C).
Как правило, #include подразумевает использование #include-guards ("гардов") или директиву #pragma once для предотвращения двойного включения.
Условная компиляция
Условная компиляция реализуется директивами if-else #if
, #ifdef
, #ifndef
, #else
, #elif
и #endif
. Варианты #ifdef и #ifndef являются простыми сокращениями для #if defined(...) и #if !defined(...).
#if VERBOSE >= 2
printf("сообщение трассировки");
#endif
Между директивами #if и #endif допускается произвольное количество директив #elif и не более одной директивы #else. Если директива #else присутствует, то между ней и директивой #endif на данном уровне вложенности не должно быть других директив #elif.
Источники
Литература
- Ричард Столлман. The C Preprocessor. Last revised July 1992 for GCC version 2 (1992).
- Керниган Б., Ритчи Д. Язык программирования Си = The C programming language. — 2-е изд. — М.: Вильямс, 2007. — С. 304. — ISBN 0-13-110362-8.
- Гукин Д. Язык программирования Си для «чайников» = C For Dummies. — М.: Диалектика, 2006. — С. 352. — ISBN 0-7645-7068-4.