Учебники

Препроцессор C ++

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

Все директивы препроцессора начинаются с #, и перед директивой препроцессора в строке могут появляться только символы пробела. Директивы препроцессора не являются операторами C ++, поэтому они не заканчиваются точкой с запятой (;).

Вы уже видели директиву #include во всех примерах. Этот макрос используется для включения заголовочного файла в исходный файл.

Существует ряд директив препроцессора, поддерживаемых C ++, таких как #include, #define, #if, #else, #line и т. Д. Давайте рассмотрим важные директивы —

Препроцессор #define

Директива препроцессора #define создает символические константы. Символическая константа называется макросом, а общая форма директивы —

#define macro-name replacement-text 

Когда эта строка появляется в файле, все последующие вхождения макроса в этом файле будут заменены текстом замены до компиляции программы. Например —

#include <iostream>
using namespace std;

#define PI 3.14159

int main () {
   cout << "Value of PI :" << PI << endl; 

   return 0;
}

Теперь давайте выполним предварительную обработку этого кода, чтобы увидеть результат, предполагая, что у нас есть файл исходного кода. Итак, давайте скомпилируем его с опцией -E и перенаправим результат в test.p. Теперь, если вы проверите test.p, в нем будет много информации, а в нижней части вы найдете замененное значение следующим образом:

$gcc -E test.cpp > test.p

...
int main () {
   cout << "Value of PI :" << 3.14159 << endl; 
   return 0;
}

Функциональные макросы

Вы можете использовать #define для определения макроса, который будет принимать аргумент следующим образом:

Live Demo

#include <iostream>
using namespace std;

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;
   
   cout <<"The minimum is " << MIN(i, j) << endl;

   return 0;
}

Если мы скомпилируем и запустим приведенный выше код, это даст следующий результат —

The minimum is 30

Условная компиляция

Существует несколько директив, которые можно использовать для компиляции отдельных частей исходного кода вашей программы. Этот процесс называется условной компиляцией.

Условная конструкция препроцессора очень похожа на структуру выбора «если». Рассмотрим следующий код препроцессора —

#ifndef NULL
   #define NULL 0
#endif

Вы можете скомпилировать программу для отладки. Вы также можете включить или выключить отладку с помощью одного макроса следующим образом:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

Это приводит к тому, что оператор cerr компилируется в программе, если символическая константа DEBUG была определена перед директивой #ifdef DEBUG. Вы можете использовать отметку #if 0, чтобы закомментировать часть программы следующим образом:

#if 0
   code prevented from compiling
#endif

Давайте попробуем следующий пример —

Live Demo

#include <iostream>
using namespace std;
#define DEBUG

#define MIN(a,b) (((a)<(b)) ? a : b)

int main () {
   int i, j;
   
   i = 100;
   j = 30;

#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif

#if 0
   /* This is commented part */
   cout << MKSTR(HELLO C++) << endl;
#endif

   cout <<"The minimum is " << MIN(i, j) << endl;

#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif

   return 0;
}

Если мы скомпилируем и запустим приведенный выше код, это даст следующий результат —

The minimum is 30
Trace: Inside main function
Trace: Coming out of main function

Операторы # и ##

Операторы препроцессора # и ## доступны в C ++ и ANSI / ISO C. Оператор # вызывает преобразование текстового токена замены в строку, заключенную в кавычки.

Рассмотрим следующее определение макроса —

Live Demo

#include <iostream>
using namespace std;

#define MKSTR( x ) #x

int main () {

   cout << MKSTR(HELLO C++) << endl;

   return 0;
}

Если мы скомпилируем и запустим приведенный выше код, это даст следующий результат —

HELLO C++

Давайте посмотрим, как это работает. Просто понять, что препроцессор C ++ переворачивает черту —

cout << MKSTR(HELLO C++) << endl;

Выше линия будет превращена в следующую строку —

cout << "HELLO C++" << endl;

Оператор ## используется для объединения двух токенов. Вот пример —

#define CONCAT( x, y )  x ## y

Когда в программе появляется CONCAT, его аргументы объединяются и используются для замены макроса. Например, CONCAT (HELLO, C ++) заменяется на «HELLO C ++» в программе следующим образом.

Live Demo

#include <iostream>
using namespace std;

#define concat(a, b) a ## b
int main() {
   int xy = 100;
   
   cout << concat(x, y);
   return 0;
}

Если мы скомпилируем и запустим приведенный выше код, это даст следующий результат —

100

Давайте посмотрим, как это работает. Легко понять, что препроцессор C ++ преобразует —

cout << concat(x, y);

Выше строка будет преобразована в следующую строку —

cout << xy;

Предопределенные макросы C ++

C ++ предоставляет ряд предопределенных макросов, упомянутых ниже —

Sr.No Макрос и описание
1

__ЛИНИЯ__

Он содержит номер текущей строки программы, когда она компилируется.

2

__ФАЙЛ__

Это содержит текущее имя файла программы, когда это компилируется.

3

__ДАТА__

Он содержит строку вида месяц / день / год, которая является датой перевода исходного файла в объектный код.

4

__ВРЕМЯ__

Он содержит строку вида час: минута: секунда, которая является временем компиляции программы.

__ЛИНИЯ__

Он содержит номер текущей строки программы, когда она компилируется.

__ФАЙЛ__

Это содержит текущее имя файла программы, когда это компилируется.

__ДАТА__

Он содержит строку вида месяц / день / год, которая является датой перевода исходного файла в объектный код.

__ВРЕМЯ__

Он содержит строку вида час: минута: секунда, которая является временем компиляции программы.

Давайте посмотрим пример для всех вышеупомянутых макросов —

Live Demo

#include <iostream>
using namespace std;

int main () {
   cout << "Value of __LINE__ : " << __LINE__ << endl;
   cout << "Value of __FILE__ : " << __FILE__ << endl;
   cout << "Value of __DATE__ : " << __DATE__ << endl;
   cout << "Value of __TIME__ : " << __TIME__ << endl;

   return 0;
}

Если мы скомпилируем и запустим приведенный выше код, это даст следующий результат —