160 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			160 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | --- | |||
|  | title: Preprocessors | |||
|  | localeTitle: Препроцессоры | |||
|  | --- | |||
|  | ## Препроцессоры в C / CPP
 | |||
|  | 
 | |||
|  | Как видно из названия, препроцессоры - это программы, которые обрабатывают наш исходный код перед компиляцией. Существует несколько шагов, связанных с написанием программы и выполнением программы на C / C ++. Давайте посмотрим на эти шаги, прежде чем мы начнем узнавать о препроцессорах. | |||
|  | 
 | |||
|  |  | |||
|  | 
 | |||
|  | Вы можете увидеть промежуточные шаги на приведенной выше диаграмме. Исходный код, написанный программистами, хранится в файле program.c. Затем этот файл обрабатывается препроцессорами, а файл расширенного исходного кода создается с именем program. Этот расширенный файл компилируется компилятором и создается файл объектного кода с именем program.obj. Наконец, компоновщик связывает этот файл объектного кода с объектным кодом библиотечных функций для генерации исполняемого файла program.exe. | |||
|  | 
 | |||
|  | Препроцессорные программы предоставляют директивы препроцессоров, которые сообщают компилятору предварительно обработать исходный код перед компиляцией. Все эти директивы препроцессора начинаются с символа `#` (хеш). Этот символ ('#') в начале инструкции в программе C / C ++ указывает, что это предпроцессорная директива. Мы можем разместить эти предпроцессорные директивы в любой нашей программе. Примерами некоторых препроцессорных директив являются: `#include` , `#define` , `#ifndef` и т. Д. | |||
|  | 
 | |||
|  | ### Типы предпроцессорных директив:
 | |||
|  | 
 | |||
|  | 1.  макрос | |||
|  | 2.  Включение файлов | |||
|  | 3.  Условная компиляция | |||
|  | 4.  Другие директивы | |||
|  | 
 | |||
|  | ### Макросы:
 | |||
|  | 
 | |||
|  | Макросы являются частью кода в программе, которому дано какое-то имя. Всякий раз, когда это имя встречается компилятором, компилятор заменяет это имя фактическим фрагментом кода. Директива `#define` используется для определения макроса. | |||
|  | 
 | |||
|  | ```cpp | |||
|  |   #include<iostream>  | |||
|  |   #define LIMIT 3  | |||
|  |   int main()  | |||
|  |   {  | |||
|  |     for(int i=0; i < LIMIT; i++)  | |||
|  |     {  | |||
|  |       std::cout<<i<<" " ;  | |||
|  |     }  | |||
|  |       return 0;  | |||
|  |   }  | |||
|  | ``` | |||
|  | 
 | |||
|  | Вывод: | |||
|  | 
 | |||
|  | `0 1 2` | |||
|  | 
 | |||
|  | В вышеприведенной программе, когда компилятор выполняет слово `LIMIT` он заменяет его на 3. Слово `LIMIT` в определении макроса называется макромодом, а «3» - расширением макроса. | |||
|  | 
 | |||
|  | В конце определения макроса не должно быть запятой (';'). Определения макросов не нуждаются в полуточке. | |||
|  | 
 | |||
|  | ### Включение файла:
 | |||
|  | 
 | |||
|  | Этот тип предпроцессорной директивы сообщает компилятору включить файл в программу исходного кода. Существует два типа файлов, которые могут быть включены пользователем в программу: | |||
|  | 
 | |||
|  | *   \#### Файл заголовка или стандартные файлы: Эти файлы содержат определение предопределенных функций, таких как printf (), ... scanf () и т. Д. Эти файлы должны быть включены для работы с этими функциями. ... Различные функции объявляются в разных файлах заголовков. Например ... стандартные операции ввода-вывода находятся в файле «iostream», тогда как функции, которые ... выполняют строковые операции, находятся в файле «string». | |||
|  | 
 | |||
|  | #### Синтаксис:
 | |||
|  | 
 | |||
|  | `#include< file_name >` где file\_name - это имя файла, который будет включен. Скобки `<` и `>` сообщают компилятору искать файл в стандартном каталоге. | |||
|  | 
 | |||
|  | *   \#### Пользовательские файлы: Когда программа становится очень большой, целесообразно разделить ее на более мелкие файлы и включать в случае необходимости. Эти типы файлов являются определяемыми пользователем файлами. Эти файлы могут быть включены как: ... `#include"filename"` | |||
|  | 
 | |||
|  | ### Условная компиляция:
 | |||
|  | 
 | |||
|  | Условные директивы компиляции - это типы директив, которые помогают скомпилировать определенную часть программы или пропустить компиляцию некоторой определенной части программы на основе некоторых условий. Это можно сделать с помощью двух команд предварительной обработки `ifdef` и `endif` . | |||
|  | 
 | |||
|  | #### Синтаксис:
 | |||
|  | 
 | |||
|  | ```cpp | |||
|  |   ifdef macro_name  | |||
|  |     statement1;  | |||
|  |     statement2;  | |||
|  |     statement3;  | |||
|  |     .  | |||
|  |     .  | |||
|  |     .  | |||
|  |     statementN;  | |||
|  |   endif  | |||
|  | ``` | |||
|  | 
 | |||
|  | Если макрос с именем «macroname» определен, тогда блок операторов будет выполняться нормально, но если он не определен, компилятор просто пропустит этот блок операторов. | |||
|  | 
 | |||
|  | ### Другие директивы:
 | |||
|  | 
 | |||
|  | Помимо вышеуказанных директив есть еще две директивы, которые обычно не используются. Это: | |||
|  | 
 | |||
|  | 1.  \##### `#undef` Директива: Директива `#undef` используется для определения существующего макроса. Эта директива работает как: | |||
|  | 
 | |||
|  | ##### Синтаксис:
 | |||
|  | 
 | |||
|  | `#undef LIMIT` Использование этого оператора будет определять неопределенный существующий макрос LIMIT. После этого утверждения каждый оператор `#ifdef LIMIT` будет оценивать значение false. | |||
|  | 
 | |||
|  | 2.  \##### # `#pragma` директива: Эта директива является директивой специального назначения и используется для включения или отключения некоторых функций. Этот тип директив специфичен для компилятора, т. Е. Они варьируются от компилятора к компилятору. Некоторые из директив `#pragma` обсуждаются ниже: | |||
|  | 
 | |||
|  | ##### `#pragma startup` и `#pragma exit` :
 | |||
|  | 
 | |||
|  | Эти директивы помогают нам определить функции, которые необходимы для запуска до запуска программы (до того, как элемент управления переходит к main ()) и непосредственно перед выходом программы (как раз перед возвратом элемента управления из main ()). | |||
|  | 
 | |||
|  | ```cpp | |||
|  | #include<stdio.h> 
 | |||
|  |  void func1();  | |||
|  |  void func2();  | |||
|  |  #pragma startup func1  | |||
|  |  #pragma exit func2  | |||
|  |  void func1()  | |||
|  |  {  | |||
|  |     printf("Inside func1() ");  | |||
|  |  }  | |||
|  |  void func2()  | |||
|  |  {  | |||
|  |     printf("Inside func2() ");  | |||
|  |  }  | |||
|  |  int main()  | |||
|  |  {  | |||
|  |     printf("Inside main() ");  | |||
|  |   | |||
|  |     return 0;  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | Вывод:   | |||
|  | `Inside func1() Inside main() Inside func2()`   | |||
|  | Вышеприведенный код будет выдавать результат, указанный ниже при запуске на компиляторах GCC:   | |||
|  | Вывод:   | |||
|  | `Inside main()`   | |||
|  | Это происходит потому, что GCC не поддерживает запуск #pragma или выход. Однако вы можете использовать приведенный ниже код для аналогичного вывода на компиляторах GCC. | |||
|  | 
 | |||
|  | ```cpp | |||
|  | #include<stdio.h> 
 | |||
|  |  void func1();  | |||
|  |  void func2();  | |||
|  |  void __attribute__((constructor)) func1();  | |||
|  |  void __attribute__((destructor)) func2();  | |||
|  |  void func1()  | |||
|  |  {  | |||
|  |     printf("Inside func1()\n");  | |||
|  |  }  | |||
|  |  void func2()  | |||
|  |  {  | |||
|  |     printf("Inside func2()\n");  | |||
|  |  }  | |||
|  |  int main()  | |||
|  |  {  | |||
|  |     printf("Inside main()\n");  | |||
|  |   | |||
|  |     return 0;  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | ##### `#pragma warn` Директива:
 | |||
|  | 
 | |||
|  | Эта директива используется, чтобы скрыть предупреждающее сообщение, которое отображается во время компиляции. Мы можем скрыть предупреждения, как показано ниже: | |||
|  | 
 | |||
|  | ##### `#pragma warn -rvl` :
 | |||
|  | 
 | |||
|  | Эта директива скрывает предупреждение, которое возникает, когда функция, которая должна возвращать значение, не возвращает значение. | |||
|  | 
 | |||
|  | ##### `#pragma warn -par` :
 | |||
|  | 
 | |||
|  | Эта директива скрывает предупреждение, которое возникает, когда функция не использует переданные ей параметры. | |||
|  | 
 | |||
|  | ##### `#pragma warn -rch` :
 | |||
|  | 
 | |||
|  | Эта директива скрывает предупреждение, которое возникает, когда код недостижим. Например: любой код, написанный после оператора return в функции, недоступен. |