Указывает препроцессору включить содержимое указанного файла в точку, где отображается директива.
Синтаксис
#include » путь — спецификация »
#include путь — спецификация >
Комментарии
Можно организовать константы и определения макросов в включаемые файлы (также известные как заголовочные файлы), а затем использовать #include директивы для добавления их в любой исходный файл. Включаемые файлы также позволяют внедрять объявления внешних переменных и сложных типов данных. Типы можно определять и именовать только один раз во включаемом файле, созданном с этой целью.
Путь-Spec — это имя файла, которому при необходимости может предшествовать Спецификация каталога. Имя файла должно указывать на существующий файл. Синтаксис инструкции path-Spec зависит от операционной системы, в которой компилируется программа.
Сведения о том, как ссылаться на сборки в приложении C++, скомпилированном с помощью /clr , см. в разделе #using директива.
Препроцессор что это. Директива #define. Макросы. Директивы препроцессора что это. C ++ Урок #66
Обе синтаксические формы приводят #include к замене директивы всем содержимым указанного файла. Различие между двумя формами — это порядок путей, которые препроцессор ищет при неполном указании пути. В приведенной ниже таблице показывается различие между этими формами синтаксиса.
1) в том же каталоге, что и файл, содержащий #include инструкцию.
2) в каталогах открытых в данный момент файлов включения в порядке, в котором они были открыты. Поиск начинается в каталоге родительского включаемого файла, а затем выполняется в каталогах всех включаемых файлов-прародителей.
3) вдоль пути, указанного в каждом /I параметре компилятора.
1) вдоль пути, указанного в каждом /I параметре компилятора.
Как только препроцессор найдет файл с заданным именем, поиск останавливается. При заключении полной, неоднозначной спецификации пути для включаемого файла между двойными кавычками ( » » ) препроцессор выполняет поиск только по этой спецификации пути и игнорирует стандартные каталоги.
Если имя файла, заключенное в двойные кавычки, является неполным указанием пути, препроцессор сначала выполняет поиск в каталоге родительского файла. Родительский файл — это файл, содержащий #include директиву. Например, если включить файл с именем file2 в файл с именем file1, то файл file1 будет родительским.
Включаемые файлы могут быть вложенными: #include директива может находиться в файле с именем другой #include директивы. Например, file2 может включать файл3. В этом случае file1 будет по-прежнему являться родителем file2, но это было бы бабушке файл3.
Если включаемые файлы являются вложенными и при компиляции происходит в командной строке, поиск в каталоге начинается в каталоге родительского файла. Затем он переходит по каталогам всех файлов «бабушке». Таким образом, поиск начинается относительно каталога, в котором находится исходный файл, обрабатываемый в текущий момент. Если файл не найден, Поиск перемещается в каталоги, заданные /I параметром компилятора (дополнительные каталоги включаемых файлов) . Наконец, выполняется поиск каталогов, заданных INCLUDE переменной среды.
#21. Директивы #include и условной компиляции | Язык C для начинающих
в среде INCLUDE разработки Visual Studio переменная среды игнорируется. Вместо них используются значения, указанные в свойствах проекта для каталогов включения. дополнительные сведения о настройке каталогов включения в Visual Studio см. в разделе включаемые каталоги и дополнительные каталоги включаемыхданных.
В приведенном ниже примере демонстрируется включение файлов с помощью угловых скобок:
#include
В этом примере в исходную программу добавляется содержимое файла с именем stdio.h . Угловые скобки приводят препроцессору для поиска в каталогах, заданных INCLUDE переменной среды для stdio.h , после того, как он выполняет поиск в каталогах, заданных /I параметром компилятора.
В следующем примере демонстрируется включение файлов, заданных в кавычках:
#include «defs.h»
В примере добавляется содержимое файла, указанного defs.h в исходной программе. Кавычки означают, что препроцессор сначала попытается найти этот файл в каталоге, содержащем родительский исходный файл.
Для включаемых файлов поддерживается до 10 уровней вложения. После завершения обработки вложенного #include объекта препроцессор сохраняет вложенный родительский файл в исходный исходный файл.
Только для систем Майкрософт
Чтобы найти исходные файлы для включения, препроцессор сначала выполняет поиск в каталогах, заданных /I параметром компилятора. /I Если параметр отсутствует или неисправен, препроцессор использует INCLUDE переменную среды для поиска всех включаемых файлов в угловых скобках. INCLUDE Переменная среды и /I параметр компилятора могут содержать несколько путей, разделенных точкой с запятой ( ; ). Если в качестве части /I параметра или INCLUDE переменной среды отображается несколько каталогов, препроцессор ищет их в том порядке, в котором они отображаются.
Представим себе следующую команду:
CL /ID:msvcinclude myprog.c
приводит к тому, что препроцессор ищет в каталоге D:msvcinclude включаемые файлы, stdio.h например. Ниже еще один пример:
SET INCLUDE=D:msvcinclude CL myprog.c
Эта инструкция действуют точно так же. Если найти файл в обоих наборах каталогов не удастся, возникает неустранимая ошибка компилятора.
Если имя файла указано полностью для включаемого файла с путем, содержащим двоеточие (например, F:MSVCSPECIALINCLTEST.H ), препроцессор следует за путем.
Для включаемых файлов, указанных как #include «path-spec» , поиск по каталогу начинается в каталоге родительского файла, а затем продолжается через каталоги всех файлов бабушкх. То есть поиск начинается относительно каталога, содержащего обрабатываемый исходный файл. Если файл «бабушке» отсутствует, и файл по-прежнему не найден, поиск продолжается так, как если бы имя файла было заключено в угловые скобки.
КОНЕЦ Только для систем Майкрософт
Источник: learn.microsoft.com
Препроцессор языка С
В компилятор языка программирования C входит препроцессор, который осуществляет подготовку программы к компиляции. Среди прочего он, например, включает содержимое одних файлов в другие, заменяет в тексте исходного кода имена констант на их значения, удаляет символы конца строки (которые нужны только программисту, чтобы код можно было легко читать, но не нужны компилятору).
Что-то препроцессор делает по-умолчанию, а какие-то его действия программируются с помощью специальных директив в исходном коде. Директивы препроцессора начинаются со знака # и заканчиваются переходом на новую строку. В отличие от законченного выражения на языке C, в конце директив не надо ставить точку с запятой. Ниже рассматриваются наиболее распространенные директивы препроцессора и некоторые его свойства, но это далеко не все, что может делать препроцессор.
Директива #include
С этой директивой мы уже не раз встречались, подключая заголовочные файлы стандартной библиотеки языка, содержащие объявления (прототипы) функций. Когда препроцессор встречает такую директиву, то понимает, что после нее идет имя файла, и включает все содержимое указанного файла в исходный код программы. Поэтому объем кода вашей программы после обработки ее препроцессором может сильно увеличиться.
Если имя файла после директивы #include заключено в угловые скобки (например, ), то поиск заголовочного файла производится в стандартном (специально оговоренном системой) каталоге. Однако в тексте программы может встречаться и такая запись:
#include «ext.h»
В таком случае заголовочный файл в первую очередь будет искаться в текущем каталоге. Таким образом, программист сам может определять заголовочные файлы для своих проектов. Кроме того, можно указывать адрес заголовочного файла:
#include «/home/iam/project10/const.h»
Директива #define
Символические константы
С директивой препроцессора #define мы также уже знакомы. С ее помощью объявляются и определяются так называемые символические константы. Например:
#define N 100 #define HELLO «Hello. Answer the questions.»
Когда перед компиляцией исходный код будет обработан препроцессором, то все символьные константы (в примере это N и HELLO) в тексте исходного кода на языке C будут заменены на соответствующие им числовые или строковые константы.
Символические константы можно определять в любом месте исходного кода. Однако чтобы переопределить их (изменить значение), необходимо отменить предыдущее определение. Иначе возникнет если не ошибка, то предупреждение. Для удаления символической константы используют директиву #undef :
#include #define HELLO «Hello. Answer the questions.n» int main () { printf(HELLO); #undef HELLO #define HELLO «Good day. Tell us about.n» printf(HELLO); }
Если в этом примере убрать строку #undef HELLO , то при компиляции в GNU/Linux появляется предупреждение: «HELLO» переопределён.
Символические константы принято писать заглавными буквами. Это только соглашение для удобства чтения кода.
Макросы как усложненные символьные константы
С помощью директивы #define можно заменять символьными константами не только числовые и строковые константы, но почти любую часть кода:
#include #define N 100 #define PN printf(«n») #define SUM for(i=0; i int main () { int i, sum = 0; SUM; printf(«%d», sum); PN; }
Здесь в теле функции main() PN заменяется препроцессором на printf(«n») , а SUM на цикл for . Такие макроопределения (макросы) в первую очередь удобны, когда в программе часто встречается один и тот же код, но выносить его в отдельную функцию нет смысла.
В примере выше PN и SUM являются макросами без аргументов. Однако препроцессор языка программирования C позволяет определять макросы с аргументами:
#include #define DIF(a,b) (a)>(b)?(a)-(b):(b)-(a) int main () { int x = 10, y = 30; printf(«%dn», DIF(67,90)); printf(«%dn», DIF(876-x,90+y)); }
Вызов макроса DIV(67,90) в тексте программы приводит к тому, что при обработке программы препроцессором туда подставляется такое выражение (67) > (90) ? (67)-(90) : (90)-(67) . В этом выражении вычисляется разница между двумя числами с помощью условного выражения (см. урок 3). В данном случае скобки не нужны. Однако при таком разворачивании (876-x) > (90+y) ? (876-x)-(90+y) : (90+y)-(876-x) скобки подчеркивают порядок операций. Если бы вместо сложения и вычитания фигурировали операции умножения или деления, то наличие скобок было бы принципиальным.
Обратите внимание, что в имени макроса не должно быть пробелов: DIF(a,b) . Первый пробел после идентификатора означает конец символической константы и начало выражения для подстановки.
- Напишите программу, содержащую пару макросов: один вычисляет сумму элементов массива, другой выводит элементы массива на экран.
- Напишите программу, содержащую макросы с аргументами, вычисляющие площади различных геометрических фигур (например, квадрата, прямоугольника, окружности).
Директивы условной компиляции
Так называемая условная компиляция позволяет компилировать или не компилировать части кода в зависимости от наличия символьных констант или их значения.
Условное выражение для препроцессора выглядит в сокращенном варианте так:
#if … … #endif
То, что находится между #if и #endif выполняется, если выражение при #if возвращает истину. Находится там могут как директивы препроцессора так и исходный код на языке C.
Условное включение может быть расширено за счет веток #else и #elif .
Рассмотрим несколько примеров.
Если в программе константа N не равна 0, то цикл for выполнится, и массив arr заполнится нулями. Если N определена и равна 0, или не определена вообще, то цикл выполняться не будет:
#include #define N 10 int main() { int i, arr[100]; #if N for(i=0; iN; i++) { arr[i] = 0; printf(«%d «, arr[i]); } #endif printf(«n»); }
Если нужно выполнить какой-то код в зависимости от наличия символьной константы, а не ее значения, то директива #if будет выглядеть так:
#if defined(N)
Или сокращенно (что тоже самое):
#ifdef N
Когда нет уверенности, была ли определена ранее символьная константа, то можно использовать такой код:
#if !defined(N) #define N 100 #endif
Таким образом мы определим константу N, если она не была определена ранее. Такие проверки могут встречаться в многофайловых проектах. Выражение препроцессора #if !defined(N) может быть сокращено так:
#ifndef N
Условную компиляцию иногда используют при отладке программного кода, а также с ее помощью компилируют программы под конкретные операционные системы.
Помните, что препроцессор обрабатывает программу до компиляции. В двоичном коде уже отсутствуют какие-либо условные выражения для препроцессора. Поэтому в логическом выражении «препроцессорного if» не должно содержаться переменных, значение которых определяется в момент выполнения программы.
Придумайте и напишите программу, которая может быть скомпилирована по-разному в зависимости от того, определена или нет в ней какая-либо символьная константа.
Константы, определенные препроцессором
Препроцессор самостоятельно определяет пять констант. От обычных (определенных программистом) они отличаются наличием пары символов подчеркивания в начале и конце их имени.
- __DATE__ — дата компиляции;
- __FILE__ — имя компилируемого файла;
- __LINE__ — номер текущей строки исходного текста программы;
- __STDC__ — равна 1, если компилятор работает по стандарту ANSI для языка C;
- __TIME__ — время компиляции.
Если эти константы встречаются в тексте программы, то заменяются на соответствующие строки или числа. Т.к. это происходит до компиляции, то, например, мы видим дату компиляции, а не дату запуска программы на выполнение. Программа ниже выводит значение предопределенных препроцессором имен на экран:
#include #define NL printf(«n») int main () { printf(__DATE__); NL; printf(«%d»,__LINE__); NL; printf(__FILE__); NL; printf(__TIME__); NL; printf(«%d»,__STDC__); NL; }
Nov 18 2020 7 les20/10_const.c 13:27:37 1
Источник: younglinux.info
Препроцессор
Препроцессор является обязательным компонентом компилятора языка Си. Вообще весь процесс компиляции программы на языке Си разбивается на три этапа:
- Препроцессор
- Компиляция
- Линковка
Препроцессор обрабатывает исходный текст программы до ее непосредственной компиляции. Результатом работы препроцессора является полный текст программы, который передается на компиляцию в исполняемый файл.
Затем компилятор компилирует обработанный препроцессором исходный код в объектные файлы.
И на последнем этапе линкер (линковщик) объединяет (линкует) объектные файлы в один исполняемый файл или файл динамической библиотеки.
Для управления препроцессором применяются директивы, каждая из которых начинается с символа решетки # и располагается на отдельной строке. Препроцессор просматривает текст программы, находит эти директивы и должным образом обрабатывает их.