* fix: imgur to s3 for russian guide without conflict (cherry picked from commit ac90750e36b0dd1fe508c69a2277b75be48e4b95) * fix: remove extra links Co-Authored-By: Randell Dawson <5313213+RandellDawson@users.noreply.github.com> * fix: revert unrelated changes * fix: revert changes
		
			
				
	
	
		
			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 в функции, недоступен. |