Учебники

C – препроцессоры

Препроцессор 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.

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

Live Demo

#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 (‘#’), когда используется в определении макроса, преобразует параметр макроса в строковую константу. Этот оператор может использоваться только в макросе с указанным аргументом или списком параметров. Например –

Live Demo

#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!

Оператор вставки токена (##)

Оператор вставки токена (##) в определении макроса объединяет два аргумента. Он позволяет объединить два отдельных токена в определении макроса в один токен. Например –

Live Demo

#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 (ноль). Определенный оператор указан следующим образом:

Live Demo

#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, прежде чем их можно будет использовать. Список аргументов заключен в круглые скобки и должен следовать сразу за именем макроса. Пробелы между именем макроса и открытыми скобками не допускаются. Например –

Live Demo

#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;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат –