Препроцессор C не является частью компилятора, но является отдельным этапом в процессе компиляции. Проще говоря, препроцессор C — это всего лишь инструмент подстановки текста, который инструктирует компилятору выполнить необходимую предварительную обработку перед фактической компиляцией. Мы будем называть препроцессор C как CPP.
Все команды препроцессора начинаются с символа хеша (#). Это должен быть первый непустой символ, и для удобства чтения директива препроцессора должна начинаться с первого столбца. В следующем разделе перечислены все важные директивы препроцессора —
Sr.No. | Директива и описание |
---|---|
1 |
#define Заменяет макрос препроцессора. |
2 |
#включают Вставляет определенный заголовок из другого файла. |
3 |
#undef Определяет макрос препроцессора. |
4 |
#ifdef Возвращает true, если этот макрос определен. |
5 |
#ifndef Возвращает true, если этот макрос не определен. |
6 |
#если Проверяет, верно ли условие времени компиляции. |
7 |
#else Альтернатива для #if. |
8 |
#elif #else и #if в одном утверждении. |
9 |
#endif Завершает препроцессор условно. |
10 |
#ошибка Распечатывает сообщение об ошибке на stderr. |
11 |
#pragma Выдает специальные команды компилятору, используя стандартизированный метод. |
#define
Заменяет макрос препроцессора.
#включают
Вставляет определенный заголовок из другого файла.
#undef
Определяет макрос препроцессора.
#ifdef
Возвращает true, если этот макрос определен.
#ifndef
Возвращает true, если этот макрос не определен.
#если
Проверяет, верно ли условие времени компиляции.
#else
Альтернатива для #if.
#elif
#else и #if в одном утверждении.
#endif
Завершает препроцессор условно.
#ошибка
Распечатывает сообщение об ошибке на stderr.
#pragma
Выдает специальные команды компилятору, используя стандартизированный метод.
Примеры препроцессоров
Проанализируйте следующие примеры, чтобы понять различные директивы.
#define MAX_ARRAY_LENGTH 20
Эта директива указывает CPP заменять экземпляры MAX_ARRAY_LENGTH на 20. Используйте #define для констант для повышения читабельности.
#include <stdio.h> #include "myheader.h"
Эти директивы сообщают CPP, что нужно получить stdio.h из системных библиотек и добавить текст в текущий исходный файл. Следующая строка говорит CPP, чтобы получить myheader.h из локального каталога и добавить содержимое в текущий исходный файл.
#undef FILE_SIZE #define FILE_SIZE 42
Он говорит CPP, чтобы отменить определение существующего FILE_SIZE и определить его как 42.
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
Это говорит CPP, чтобы определить СООБЩЕНИЕ, только если СООБЩЕНИЕ еще не определено.
#ifdef DEBUG /* Your debugging statements here */ #endif
Он говорит CPP обрабатывать приложенные операторы, если определен DEBUG. Это полезно, если вы передаете флаг -DDEBUG компилятору gcc во время компиляции. Это определит DEBUG, так что вы можете включать и выключать отладку на лету во время компиляции.
Предопределенные макросы
ANSI C определяет количество макросов. Хотя каждый из них доступен для использования в программировании, предопределенные макросы не должны изменяться напрямую.
Sr.No. | Макрос и описание |
---|---|
1 |
__ДАТА__ Текущая дата в виде символьного литерала в формате «МММ ДД ГГГГ». |
2 |
__ВРЕМЯ__ Текущее время как символьный литерал в формате «ЧЧ: ММ: СС». |
3 |
__ФАЙЛ__ Это содержит текущее имя файла в виде строкового литерала. |
4 |
__ЛИНИЯ__ Он содержит номер текущей строки в виде десятичной константы. |
5 |
__STDC__ Определяется как 1, когда компилятор соответствует стандарту ANSI. |
__ДАТА__
Текущая дата в виде символьного литерала в формате «МММ ДД ГГГГ».
__ВРЕМЯ__
Текущее время как символьный литерал в формате «ЧЧ: ММ: СС».
__ФАЙЛ__
Это содержит текущее имя файла в виде строкового литерала.
__ЛИНИЯ__
Он содержит номер текущей строки в виде десятичной константы.
__STDC__
Определяется как 1, когда компилятор соответствует стандарту ANSI.
Давайте попробуем следующий пример —
#include <stdio.h> int main() { printf("File :%s\n", __FILE__ ); printf("Date :%s\n", __DATE__ ); printf("Time :%s\n", __TIME__ ); printf("Line :%d\n", __LINE__ ); printf("ANSI :%d\n", __STDC__ ); }
Когда приведенный выше код в файле test.c компилируется и выполняется, он дает следующий результат —
File :test.c Date :Jun 2 2012 Time :03:36:24 Line :8 ANSI :1
Операторы препроцессора
Препроцессор C предлагает следующие операторы для создания макросов:
Оператор продолжения макроса (\)
Макрос обычно ограничен одной строкой. Оператор продолжения макроса (\) используется для продолжения макроса, который слишком длинный для одной строки. Например —
#define message_for(a, b) \ printf(#a " and " #b ": We love you!\n")
Оператор Stringize (#)
Оператор stringize или number-sign (‘#’), когда используется в определении макроса, преобразует параметр макроса в строковую константу. Этот оператор может использоваться только в макросе с указанным аргументом или списком параметров. Например —
#include <stdio.h> #define message_for(a, b) \ printf(#a " and " #b ": We love you!\n") int main(void) { message_for(Carole, Debra); return 0; }
Когда приведенный выше код компилируется и выполняется, он дает следующий результат —
Carole and Debra: We love you!
Оператор вставки токена (##)
Оператор вставки токена (##) в определении макроса объединяет два аргумента. Он позволяет объединить два отдельных токена в определении макроса в один токен. Например —
#include <stdio.h> #define tokenpaster(n) printf ("token" #n " = %d", token##n) int main(void) { int token34 = 40; tokenpaster(34); return 0; }
Когда приведенный выше код компилируется и выполняется, он дает следующий результат —
token34 = 40
Это произошло так, потому что этот пример приводит к следующему фактическому выводу препроцессора —
printf ("token34 = %d", token34);
В этом примере показано объединение токена ## n в token34, и здесь мы использовали как stringize, так и вставку токена .
Определенный () оператор
Определяемый препроцессором оператор используется в константных выражениях, чтобы определить, определен ли идентификатор с помощью #define. Если указанный идентификатор определен, значение равно true (не ноль). Если символ не определен, значение равно false (ноль). Определенный оператор указан следующим образом:
#include <stdio.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { printf("Here is the message: %s\n", MESSAGE); return 0; }
Когда приведенный выше код компилируется и выполняется, он дает следующий результат —
Here is the message: You wish!
Параметризованные макросы
Одной из мощных функций CPP является возможность имитировать функции с помощью параметризованных макросов. Например, у нас может быть некоторый код для возведения в квадрат числа следующим образом:
int square(int x) { return x * x; }
Мы можем переписать код выше с помощью макроса следующим образом:
#define square(x) ((x) * (x))
Макросы с аргументами должны быть определены с использованием директивы #define, прежде чем их можно будет использовать. Список аргументов заключен в круглые скобки и должен следовать сразу за именем макроса. Пробелы между именем макроса и открытыми скобками не допускаются. Например —
#include <stdio.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { printf("Max between 20 and 10 is %d\n", MAX(10, 20)); return 0; }
Когда приведенный выше код компилируется и выполняется, он дает следующий результат —